1108f7bbaSPaul Durrant /*
2108f7bbaSPaul Durrant * Copyright (c) 2018 Citrix Systems Inc.
3108f7bbaSPaul Durrant *
4108f7bbaSPaul Durrant * This work is licensed under the terms of the GNU GPL, version 2 or later.
5108f7bbaSPaul Durrant * See the COPYING file in the top-level directory.
6108f7bbaSPaul Durrant */
7108f7bbaSPaul Durrant
8108f7bbaSPaul Durrant #include "qemu/osdep.h"
982a29e30SPaul Durrant #include "qemu/main-loop.h"
100b8fa32fSMarkus Armbruster #include "qemu/module.h"
1182a29e30SPaul Durrant #include "qemu/uuid.h"
12a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
13108f7bbaSPaul Durrant #include "hw/sysbus.h"
14094a2239SPaul Durrant #include "hw/xen/xen.h"
15a783f8adSPaul Durrant #include "hw/xen/xen-backend.h"
16*0973996fSPaolo Bonzini #include "hw/xen/xen-legacy-backend.h" /* xen_be_init() */
17108f7bbaSPaul Durrant #include "hw/xen/xen-bus.h"
18094a2239SPaul Durrant #include "hw/xen/xen-bus-helper.h"
19094a2239SPaul Durrant #include "monitor/monitor.h"
20108f7bbaSPaul Durrant #include "qapi/error.h"
21a783f8adSPaul Durrant #include "qapi/qmp/qdict.h"
22094a2239SPaul Durrant #include "sysemu/sysemu.h"
237d6eff13SDavid Woodhouse #include "net/net.h"
24108f7bbaSPaul Durrant #include "trace.h"
25108f7bbaSPaul Durrant
xen_device_get_backend_path(XenDevice * xendev)26094a2239SPaul Durrant static char *xen_device_get_backend_path(XenDevice *xendev)
27094a2239SPaul Durrant {
28094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
29094a2239SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
30094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
31094a2239SPaul Durrant const char *backend = xendev_class->backend;
32094a2239SPaul Durrant
33094a2239SPaul Durrant if (!backend) {
34094a2239SPaul Durrant backend = type;
35094a2239SPaul Durrant }
36094a2239SPaul Durrant
37094a2239SPaul Durrant return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s",
38094a2239SPaul Durrant xenbus->backend_id, backend, xendev->frontend_id,
39094a2239SPaul Durrant xendev->name);
40094a2239SPaul Durrant }
41094a2239SPaul Durrant
xen_device_get_frontend_path(XenDevice * xendev)42094a2239SPaul Durrant static char *xen_device_get_frontend_path(XenDevice *xendev)
43094a2239SPaul Durrant {
44094a2239SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
45094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
46094a2239SPaul Durrant const char *device = xendev_class->device;
47094a2239SPaul Durrant
48094a2239SPaul Durrant if (!device) {
49094a2239SPaul Durrant device = type;
50094a2239SPaul Durrant }
51094a2239SPaul Durrant
52094a2239SPaul Durrant return g_strdup_printf("/local/domain/%u/device/%s/%s",
53094a2239SPaul Durrant xendev->frontend_id, device, xendev->name);
54094a2239SPaul Durrant }
55094a2239SPaul Durrant
xen_device_unplug(XenDevice * xendev,Error ** errp)56b6af8926SPaul Durrant static void xen_device_unplug(XenDevice *xendev, Error **errp)
57b6af8926SPaul Durrant {
581de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD();
59b6af8926SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
60b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
61b6af8926SPaul Durrant xs_transaction_t tid;
62b6af8926SPaul Durrant
63b6af8926SPaul Durrant trace_xen_device_unplug(type, xendev->name);
64b6af8926SPaul Durrant
65b6af8926SPaul Durrant /* Mimic the way the Xen toolstack does an unplug */
66b6af8926SPaul Durrant again:
67ba2a92dbSPaul Durrant tid = qemu_xen_xs_transaction_start(xenbus->xsh);
68b6af8926SPaul Durrant if (tid == XBT_NULL) {
69b6af8926SPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_start");
70b6af8926SPaul Durrant return;
71b6af8926SPaul Durrant }
72b6af8926SPaul Durrant
73b6af8926SPaul Durrant xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online",
741de7096dSVladimir Sementsov-Ogievskiy errp, "%u", 0);
751de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
76b6af8926SPaul Durrant goto abort;
77b6af8926SPaul Durrant }
78b6af8926SPaul Durrant
79b6af8926SPaul Durrant xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state",
801de7096dSVladimir Sementsov-Ogievskiy errp, "%u", XenbusStateClosing);
811de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
82b6af8926SPaul Durrant goto abort;
83b6af8926SPaul Durrant }
84b6af8926SPaul Durrant
85ba2a92dbSPaul Durrant if (!qemu_xen_xs_transaction_end(xenbus->xsh, tid, false)) {
86b6af8926SPaul Durrant if (errno == EAGAIN) {
87b6af8926SPaul Durrant goto again;
88b6af8926SPaul Durrant }
89b6af8926SPaul Durrant
90b6af8926SPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end");
91b6af8926SPaul Durrant }
92b6af8926SPaul Durrant
93b6af8926SPaul Durrant return;
94b6af8926SPaul Durrant
95b6af8926SPaul Durrant abort:
96b6af8926SPaul Durrant /*
97b6af8926SPaul Durrant * We only abort if there is already a failure so ignore any error
98b6af8926SPaul Durrant * from ending the transaction.
99b6af8926SPaul Durrant */
100ba2a92dbSPaul Durrant qemu_xen_xs_transaction_end(xenbus->xsh, tid, true);
101b6af8926SPaul Durrant }
102b6af8926SPaul Durrant
xen_bus_print_dev(Monitor * mon,DeviceState * dev,int indent)103094a2239SPaul Durrant static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent)
104094a2239SPaul Durrant {
105094a2239SPaul Durrant XenDevice *xendev = XEN_DEVICE(dev);
106094a2239SPaul Durrant
107094a2239SPaul Durrant monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n",
108094a2239SPaul Durrant indent, "", xendev->name, xendev->frontend_id);
109094a2239SPaul Durrant }
110094a2239SPaul Durrant
xen_bus_get_dev_path(DeviceState * dev)111094a2239SPaul Durrant static char *xen_bus_get_dev_path(DeviceState *dev)
112094a2239SPaul Durrant {
113094a2239SPaul Durrant return xen_device_get_backend_path(XEN_DEVICE(dev));
114094a2239SPaul Durrant }
115094a2239SPaul Durrant
xen_bus_backend_create(XenBus * xenbus,const char * type,const char * name,char * path,Error ** errp)116a783f8adSPaul Durrant static void xen_bus_backend_create(XenBus *xenbus, const char *type,
117a783f8adSPaul Durrant const char *name, char *path,
118a783f8adSPaul Durrant Error **errp)
119a783f8adSPaul Durrant {
1201de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD();
121a783f8adSPaul Durrant xs_transaction_t tid;
122a783f8adSPaul Durrant char **key;
123a783f8adSPaul Durrant QDict *opts;
124a783f8adSPaul Durrant unsigned int i, n;
125a783f8adSPaul Durrant
126a783f8adSPaul Durrant trace_xen_bus_backend_create(type, path);
127a783f8adSPaul Durrant
128a783f8adSPaul Durrant again:
129ba2a92dbSPaul Durrant tid = qemu_xen_xs_transaction_start(xenbus->xsh);
130a783f8adSPaul Durrant if (tid == XBT_NULL) {
131a783f8adSPaul Durrant error_setg(errp, "failed xs_transaction_start");
132a783f8adSPaul Durrant return;
133a783f8adSPaul Durrant }
134a783f8adSPaul Durrant
135ba2a92dbSPaul Durrant key = qemu_xen_xs_directory(xenbus->xsh, tid, path, &n);
136a783f8adSPaul Durrant if (!key) {
137ba2a92dbSPaul Durrant if (!qemu_xen_xs_transaction_end(xenbus->xsh, tid, true)) {
138a783f8adSPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end");
139a783f8adSPaul Durrant }
140a783f8adSPaul Durrant return;
141a783f8adSPaul Durrant }
142a783f8adSPaul Durrant
143a783f8adSPaul Durrant opts = qdict_new();
144a783f8adSPaul Durrant for (i = 0; i < n; i++) {
145a783f8adSPaul Durrant char *val;
146a783f8adSPaul Durrant
147a783f8adSPaul Durrant /*
148a783f8adSPaul Durrant * Assume anything found in the xenstore backend area, other than
149a783f8adSPaul Durrant * the keys created for a generic XenDevice, are parameters
150a783f8adSPaul Durrant * to be used to configure the backend.
151a783f8adSPaul Durrant */
152a783f8adSPaul Durrant if (!strcmp(key[i], "state") ||
153a783f8adSPaul Durrant !strcmp(key[i], "online") ||
154a783f8adSPaul Durrant !strcmp(key[i], "frontend") ||
155a783f8adSPaul Durrant !strcmp(key[i], "frontend-id") ||
156a783f8adSPaul Durrant !strcmp(key[i], "hotplug-status"))
157a783f8adSPaul Durrant continue;
158a783f8adSPaul Durrant
159a783f8adSPaul Durrant if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms",
160a783f8adSPaul Durrant &val) == 1) {
161a783f8adSPaul Durrant qdict_put_str(opts, key[i], val);
162a783f8adSPaul Durrant free(val);
163a783f8adSPaul Durrant }
164a783f8adSPaul Durrant }
165a783f8adSPaul Durrant
166a783f8adSPaul Durrant free(key);
167a783f8adSPaul Durrant
168ba2a92dbSPaul Durrant if (!qemu_xen_xs_transaction_end(xenbus->xsh, tid, false)) {
169a783f8adSPaul Durrant qobject_unref(opts);
170a783f8adSPaul Durrant
171a783f8adSPaul Durrant if (errno == EAGAIN) {
172a783f8adSPaul Durrant goto again;
173a783f8adSPaul Durrant }
174a783f8adSPaul Durrant
175a783f8adSPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end");
176a783f8adSPaul Durrant return;
177a783f8adSPaul Durrant }
178a783f8adSPaul Durrant
1791de7096dSVladimir Sementsov-Ogievskiy xen_backend_device_create(xenbus, type, name, opts, errp);
180a783f8adSPaul Durrant qobject_unref(opts);
181a783f8adSPaul Durrant
1821de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
1831de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to create '%s' device '%s': ", type, name);
184a783f8adSPaul Durrant }
185a783f8adSPaul Durrant }
186a783f8adSPaul Durrant
xen_bus_type_enumerate(XenBus * xenbus,const char * type)187a783f8adSPaul Durrant static void xen_bus_type_enumerate(XenBus *xenbus, const char *type)
188a783f8adSPaul Durrant {
189a783f8adSPaul Durrant char *domain_path = g_strdup_printf("backend/%s/%u", type, xen_domid);
190a783f8adSPaul Durrant char **backend;
191a783f8adSPaul Durrant unsigned int i, n;
192a783f8adSPaul Durrant
193a783f8adSPaul Durrant trace_xen_bus_type_enumerate(type);
194a783f8adSPaul Durrant
195ba2a92dbSPaul Durrant backend = qemu_xen_xs_directory(xenbus->xsh, XBT_NULL, domain_path, &n);
196a783f8adSPaul Durrant if (!backend) {
197a783f8adSPaul Durrant goto out;
198a783f8adSPaul Durrant }
199a783f8adSPaul Durrant
200a783f8adSPaul Durrant for (i = 0; i < n; i++) {
201a783f8adSPaul Durrant char *backend_path = g_strdup_printf("%s/%s", domain_path,
202a783f8adSPaul Durrant backend[i]);
2033809f758SPaul Durrant enum xenbus_state state;
2043809f758SPaul Durrant unsigned int online;
205a783f8adSPaul Durrant
206a783f8adSPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "state",
2073809f758SPaul Durrant NULL, "%u", &state) != 1)
2083809f758SPaul Durrant state = XenbusStateUnknown;
209a783f8adSPaul Durrant
2103809f758SPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "online",
2113809f758SPaul Durrant NULL, "%u", &online) != 1)
2123809f758SPaul Durrant online = 0;
2133809f758SPaul Durrant
214eb6ae7a6SDavid Woodhouse if (online && state == XenbusStateInitialising &&
215eb6ae7a6SDavid Woodhouse !xen_backend_exists(type, backend[i])) {
216a783f8adSPaul Durrant Error *local_err = NULL;
217a783f8adSPaul Durrant
218a783f8adSPaul Durrant xen_bus_backend_create(xenbus, type, backend[i], backend_path,
219a783f8adSPaul Durrant &local_err);
220a783f8adSPaul Durrant if (local_err) {
221a783f8adSPaul Durrant error_report_err(local_err);
222a783f8adSPaul Durrant }
223a783f8adSPaul Durrant }
224a783f8adSPaul Durrant
225a783f8adSPaul Durrant g_free(backend_path);
226a783f8adSPaul Durrant }
227a783f8adSPaul Durrant
228a783f8adSPaul Durrant free(backend);
229a783f8adSPaul Durrant
230a783f8adSPaul Durrant out:
231a783f8adSPaul Durrant g_free(domain_path);
232a783f8adSPaul Durrant }
233a783f8adSPaul Durrant
xen_bus_enumerate(XenBus * xenbus)2343809f758SPaul Durrant static void xen_bus_enumerate(XenBus *xenbus)
235a783f8adSPaul Durrant {
236a783f8adSPaul Durrant char **type;
237a783f8adSPaul Durrant unsigned int i, n;
238a783f8adSPaul Durrant
239a783f8adSPaul Durrant trace_xen_bus_enumerate();
240a783f8adSPaul Durrant
241ba2a92dbSPaul Durrant type = qemu_xen_xs_directory(xenbus->xsh, XBT_NULL, "backend", &n);
242a783f8adSPaul Durrant if (!type) {
243a783f8adSPaul Durrant return;
244a783f8adSPaul Durrant }
245a783f8adSPaul Durrant
246a783f8adSPaul Durrant for (i = 0; i < n; i++) {
247a783f8adSPaul Durrant xen_bus_type_enumerate(xenbus, type[i]);
248a783f8adSPaul Durrant }
249a783f8adSPaul Durrant
250a783f8adSPaul Durrant free(type);
251a783f8adSPaul Durrant }
252a783f8adSPaul Durrant
xen_bus_device_cleanup(XenDevice * xendev)2533809f758SPaul Durrant static void xen_bus_device_cleanup(XenDevice *xendev)
2543809f758SPaul Durrant {
2553809f758SPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
2563809f758SPaul Durrant Error *local_err = NULL;
2573809f758SPaul Durrant
2583809f758SPaul Durrant trace_xen_bus_device_cleanup(type, xendev->name);
2593809f758SPaul Durrant
2603809f758SPaul Durrant g_assert(!xendev->backend_online);
2613809f758SPaul Durrant
2623809f758SPaul Durrant if (!xen_backend_try_device_destroy(xendev, &local_err)) {
2633809f758SPaul Durrant object_unparent(OBJECT(xendev));
2643809f758SPaul Durrant }
2653809f758SPaul Durrant
2663809f758SPaul Durrant if (local_err) {
2673809f758SPaul Durrant error_report_err(local_err);
2683809f758SPaul Durrant }
2693809f758SPaul Durrant }
2703809f758SPaul Durrant
xen_bus_cleanup(XenBus * xenbus)2713809f758SPaul Durrant static void xen_bus_cleanup(XenBus *xenbus)
2723809f758SPaul Durrant {
2733809f758SPaul Durrant XenDevice *xendev, *next;
2743809f758SPaul Durrant
2753809f758SPaul Durrant trace_xen_bus_cleanup();
2763809f758SPaul Durrant
2773809f758SPaul Durrant QLIST_FOREACH_SAFE(xendev, &xenbus->inactive_devices, list, next) {
2783809f758SPaul Durrant g_assert(xendev->inactive);
2793809f758SPaul Durrant QLIST_REMOVE(xendev, list);
2803809f758SPaul Durrant xen_bus_device_cleanup(xendev);
2813809f758SPaul Durrant }
2823809f758SPaul Durrant }
2833809f758SPaul Durrant
xen_bus_backend_changed(void * opaque,const char * path)284ba2a92dbSPaul Durrant static void xen_bus_backend_changed(void *opaque, const char *path)
2853809f758SPaul Durrant {
2863809f758SPaul Durrant XenBus *xenbus = opaque;
2873809f758SPaul Durrant
2883809f758SPaul Durrant xen_bus_enumerate(xenbus);
2893809f758SPaul Durrant xen_bus_cleanup(xenbus);
2903809f758SPaul Durrant }
2913809f758SPaul Durrant
xen_bus_unrealize(BusState * bus)292b69c3c21SMarkus Armbruster static void xen_bus_unrealize(BusState *bus)
293108f7bbaSPaul Durrant {
294094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(bus);
295094a2239SPaul Durrant
296108f7bbaSPaul Durrant trace_xen_bus_unrealize();
297094a2239SPaul Durrant
298a783f8adSPaul Durrant if (xenbus->backend_watch) {
299c4583c8cSPaul Durrant unsigned int i;
300c4583c8cSPaul Durrant
301c4583c8cSPaul Durrant for (i = 0; i < xenbus->backend_types; i++) {
302c4583c8cSPaul Durrant if (xenbus->backend_watch[i]) {
303ba2a92dbSPaul Durrant xs_node_unwatch(xenbus->xsh, xenbus->backend_watch[i]);
304c4583c8cSPaul Durrant }
305c4583c8cSPaul Durrant }
306c4583c8cSPaul Durrant
307c4583c8cSPaul Durrant g_free(xenbus->backend_watch);
308a783f8adSPaul Durrant xenbus->backend_watch = NULL;
309a783f8adSPaul Durrant }
310a783f8adSPaul Durrant
311374752a2SPaul Durrant if (xenbus->xsh) {
312ba2a92dbSPaul Durrant qemu_xen_xs_close(xenbus->xsh);
313108f7bbaSPaul Durrant }
31482a29e30SPaul Durrant }
31582a29e30SPaul Durrant
xen_bus_realize(BusState * bus,Error ** errp)316108f7bbaSPaul Durrant static void xen_bus_realize(BusState *bus, Error **errp)
317108f7bbaSPaul Durrant {
318c4583c8cSPaul Durrant char *key = g_strdup_printf("%u", xen_domid);
319094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(bus);
320094a2239SPaul Durrant unsigned int domid;
321c4583c8cSPaul Durrant const char **type;
322c4583c8cSPaul Durrant unsigned int i;
323a783f8adSPaul Durrant Error *local_err = NULL;
324094a2239SPaul Durrant
325108f7bbaSPaul Durrant trace_xen_bus_realize();
326094a2239SPaul Durrant
327ba2a92dbSPaul Durrant xenbus->xsh = qemu_xen_xs_open();
328094a2239SPaul Durrant if (!xenbus->xsh) {
329094a2239SPaul Durrant error_setg_errno(errp, errno, "failed xs_open");
330094a2239SPaul Durrant goto fail;
331094a2239SPaul Durrant }
332094a2239SPaul Durrant
333*0973996fSPaolo Bonzini /* Initialize legacy backend core & drivers */
334*0973996fSPaolo Bonzini xen_be_init();
335*0973996fSPaolo Bonzini
336094a2239SPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */
337094a2239SPaul Durrant "domid", NULL, "%u", &domid) == 1) {
338094a2239SPaul Durrant xenbus->backend_id = domid;
339094a2239SPaul Durrant } else {
340094a2239SPaul Durrant xenbus->backend_id = 0; /* Assume lack of node means dom0 */
341094a2239SPaul Durrant }
342094a2239SPaul Durrant
343a783f8adSPaul Durrant module_call_init(MODULE_INIT_XEN_BACKEND);
344a783f8adSPaul Durrant
345c4583c8cSPaul Durrant type = xen_backend_get_types(&xenbus->backend_types);
346ba2a92dbSPaul Durrant xenbus->backend_watch = g_new(struct qemu_xs_watch *,
347ba2a92dbSPaul Durrant xenbus->backend_types);
348c4583c8cSPaul Durrant
349c4583c8cSPaul Durrant for (i = 0; i < xenbus->backend_types; i++) {
350c4583c8cSPaul Durrant char *node = g_strdup_printf("backend/%s", type[i]);
351c4583c8cSPaul Durrant
352c4583c8cSPaul Durrant xenbus->backend_watch[i] =
353ba2a92dbSPaul Durrant xs_node_watch(xenbus->xsh, node, key, xen_bus_backend_changed,
354ba2a92dbSPaul Durrant xenbus, &local_err);
355a783f8adSPaul Durrant if (local_err) {
356a783f8adSPaul Durrant /* This need not be treated as a hard error so don't propagate */
357a783f8adSPaul Durrant error_reportf_err(local_err,
358c4583c8cSPaul Durrant "failed to set up '%s' enumeration watch: ",
359c4583c8cSPaul Durrant type[i]);
360a783f8adSPaul Durrant }
361a783f8adSPaul Durrant
362c4583c8cSPaul Durrant g_free(node);
363c4583c8cSPaul Durrant }
364c4583c8cSPaul Durrant
365c4583c8cSPaul Durrant g_free(type);
366c4583c8cSPaul Durrant g_free(key);
367094a2239SPaul Durrant return;
368094a2239SPaul Durrant
369094a2239SPaul Durrant fail:
370b69c3c21SMarkus Armbruster xen_bus_unrealize(bus);
371c4583c8cSPaul Durrant g_free(key);
372108f7bbaSPaul Durrant }
373108f7bbaSPaul Durrant
xen_bus_unplug_request(HotplugHandler * hotplug,DeviceState * dev,Error ** errp)374b6af8926SPaul Durrant static void xen_bus_unplug_request(HotplugHandler *hotplug,
375b6af8926SPaul Durrant DeviceState *dev,
376b6af8926SPaul Durrant Error **errp)
377b6af8926SPaul Durrant {
378b6af8926SPaul Durrant XenDevice *xendev = XEN_DEVICE(dev);
379b6af8926SPaul Durrant
380b6af8926SPaul Durrant xen_device_unplug(xendev, errp);
381b6af8926SPaul Durrant }
382b6af8926SPaul Durrant
xen_bus_class_init(ObjectClass * class,void * data)383108f7bbaSPaul Durrant static void xen_bus_class_init(ObjectClass *class, void *data)
384108f7bbaSPaul Durrant {
385108f7bbaSPaul Durrant BusClass *bus_class = BUS_CLASS(class);
386b6af8926SPaul Durrant HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class);
387108f7bbaSPaul Durrant
388094a2239SPaul Durrant bus_class->print_dev = xen_bus_print_dev;
389094a2239SPaul Durrant bus_class->get_dev_path = xen_bus_get_dev_path;
390108f7bbaSPaul Durrant bus_class->realize = xen_bus_realize;
391108f7bbaSPaul Durrant bus_class->unrealize = xen_bus_unrealize;
392b6af8926SPaul Durrant
393b6af8926SPaul Durrant hotplug_class->unplug_request = xen_bus_unplug_request;
394108f7bbaSPaul Durrant }
395108f7bbaSPaul Durrant
396108f7bbaSPaul Durrant static const TypeInfo xen_bus_type_info = {
397108f7bbaSPaul Durrant .name = TYPE_XEN_BUS,
398108f7bbaSPaul Durrant .parent = TYPE_BUS,
399108f7bbaSPaul Durrant .instance_size = sizeof(XenBus),
400108f7bbaSPaul Durrant .class_size = sizeof(XenBusClass),
401108f7bbaSPaul Durrant .class_init = xen_bus_class_init,
402108f7bbaSPaul Durrant .interfaces = (InterfaceInfo[]) {
403108f7bbaSPaul Durrant { TYPE_HOTPLUG_HANDLER },
404108f7bbaSPaul Durrant { }
405108f7bbaSPaul Durrant },
406108f7bbaSPaul Durrant };
407108f7bbaSPaul Durrant
xen_device_backend_printf(XenDevice * xendev,const char * key,const char * fmt,...)408b6af8926SPaul Durrant void xen_device_backend_printf(XenDevice *xendev, const char *key,
409094a2239SPaul Durrant const char *fmt, ...)
410094a2239SPaul Durrant {
411094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
412094a2239SPaul Durrant Error *local_err = NULL;
413094a2239SPaul Durrant va_list ap;
414094a2239SPaul Durrant
415094a2239SPaul Durrant g_assert(xenbus->xsh);
416094a2239SPaul Durrant
417094a2239SPaul Durrant va_start(ap, fmt);
418094a2239SPaul Durrant xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
419094a2239SPaul Durrant &local_err, fmt, ap);
420094a2239SPaul Durrant va_end(ap);
421094a2239SPaul Durrant
422094a2239SPaul Durrant if (local_err) {
423094a2239SPaul Durrant error_report_err(local_err);
424094a2239SPaul Durrant }
425094a2239SPaul Durrant }
426094a2239SPaul Durrant
427d62449daSDaniel P. Berrangé G_GNUC_SCANF(3, 4)
xen_device_backend_scanf(XenDevice * xendev,const char * key,const char * fmt,...)42882a29e30SPaul Durrant static int xen_device_backend_scanf(XenDevice *xendev, const char *key,
42982a29e30SPaul Durrant const char *fmt, ...)
43082a29e30SPaul Durrant {
43182a29e30SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
43282a29e30SPaul Durrant va_list ap;
43382a29e30SPaul Durrant int rc;
43482a29e30SPaul Durrant
43582a29e30SPaul Durrant g_assert(xenbus->xsh);
43682a29e30SPaul Durrant
43782a29e30SPaul Durrant va_start(ap, fmt);
43882a29e30SPaul Durrant rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
43982a29e30SPaul Durrant NULL, fmt, ap);
44082a29e30SPaul Durrant va_end(ap);
44182a29e30SPaul Durrant
44282a29e30SPaul Durrant return rc;
44382a29e30SPaul Durrant }
44482a29e30SPaul Durrant
xen_device_backend_set_state(XenDevice * xendev,enum xenbus_state state)44582a29e30SPaul Durrant void xen_device_backend_set_state(XenDevice *xendev,
446094a2239SPaul Durrant enum xenbus_state state)
447094a2239SPaul Durrant {
448094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
449094a2239SPaul Durrant
450094a2239SPaul Durrant if (xendev->backend_state == state) {
451094a2239SPaul Durrant return;
452094a2239SPaul Durrant }
453094a2239SPaul Durrant
454094a2239SPaul Durrant trace_xen_device_backend_state(type, xendev->name,
455094a2239SPaul Durrant xs_strstate(state));
456094a2239SPaul Durrant
457094a2239SPaul Durrant xendev->backend_state = state;
458094a2239SPaul Durrant xen_device_backend_printf(xendev, "state", "%u", state);
459094a2239SPaul Durrant }
460094a2239SPaul Durrant
xen_device_backend_get_state(XenDevice * xendev)46182a29e30SPaul Durrant enum xenbus_state xen_device_backend_get_state(XenDevice *xendev)
46282a29e30SPaul Durrant {
46382a29e30SPaul Durrant return xendev->backend_state;
46482a29e30SPaul Durrant }
46582a29e30SPaul Durrant
xen_device_backend_set_online(XenDevice * xendev,bool online)466b6af8926SPaul Durrant static void xen_device_backend_set_online(XenDevice *xendev, bool online)
467b6af8926SPaul Durrant {
468b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
469b6af8926SPaul Durrant
470b6af8926SPaul Durrant if (xendev->backend_online == online) {
471b6af8926SPaul Durrant return;
472b6af8926SPaul Durrant }
473b6af8926SPaul Durrant
474b6af8926SPaul Durrant trace_xen_device_backend_online(type, xendev->name, online);
475b6af8926SPaul Durrant
476b6af8926SPaul Durrant xendev->backend_online = online;
477b6af8926SPaul Durrant xen_device_backend_printf(xendev, "online", "%u", online);
478b6af8926SPaul Durrant }
479b6af8926SPaul Durrant
480cb323146SAnthony PERARD /*
481cb323146SAnthony PERARD * Tell from the state whether the frontend is likely alive,
482cb323146SAnthony PERARD * i.e. it will react to a change of state of the backend.
483cb323146SAnthony PERARD */
xen_device_frontend_is_active(XenDevice * xendev)4843809f758SPaul Durrant static bool xen_device_frontend_is_active(XenDevice *xendev)
485cb323146SAnthony PERARD {
4863809f758SPaul Durrant switch (xendev->frontend_state) {
487cb323146SAnthony PERARD case XenbusStateInitWait:
488cb323146SAnthony PERARD case XenbusStateInitialised:
489cb323146SAnthony PERARD case XenbusStateConnected:
490cb323146SAnthony PERARD case XenbusStateClosing:
491cb323146SAnthony PERARD return true;
492cb323146SAnthony PERARD default:
493cb323146SAnthony PERARD return false;
494cb323146SAnthony PERARD }
495cb323146SAnthony PERARD }
496cb323146SAnthony PERARD
xen_device_backend_changed(void * opaque,const char * path)497ba2a92dbSPaul Durrant static void xen_device_backend_changed(void *opaque, const char *path)
498b6af8926SPaul Durrant {
499b6af8926SPaul Durrant XenDevice *xendev = opaque;
500b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
501b6af8926SPaul Durrant enum xenbus_state state;
502b6af8926SPaul Durrant unsigned int online;
503b6af8926SPaul Durrant
504b6af8926SPaul Durrant trace_xen_device_backend_changed(type, xendev->name);
505b6af8926SPaul Durrant
506b6af8926SPaul Durrant if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) {
507b6af8926SPaul Durrant state = XenbusStateUnknown;
508b6af8926SPaul Durrant }
509b6af8926SPaul Durrant
510b6af8926SPaul Durrant xen_device_backend_set_state(xendev, state);
511b6af8926SPaul Durrant
512b6af8926SPaul Durrant if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
513b6af8926SPaul Durrant online = 0;
514b6af8926SPaul Durrant }
515b6af8926SPaul Durrant
516b6af8926SPaul Durrant xen_device_backend_set_online(xendev, !!online);
517b6af8926SPaul Durrant
518b6af8926SPaul Durrant /*
519b6af8926SPaul Durrant * If the toolstack (or unplug request callback) has set the backend
520cb323146SAnthony PERARD * state to Closing, but there is no active frontend then set the
521cb323146SAnthony PERARD * backend state to Closed.
522b6af8926SPaul Durrant */
5233809f758SPaul Durrant if (state == XenbusStateClosing &&
5243809f758SPaul Durrant !xen_device_frontend_is_active(xendev)) {
525b6af8926SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateClosed);
526b6af8926SPaul Durrant }
527b6af8926SPaul Durrant
528b6af8926SPaul Durrant /*
52967bc8e00SPaul Durrant * If a backend is still 'online' then we should leave it alone but,
5303809f758SPaul Durrant * if a backend is not 'online', then the device is a candidate
5313809f758SPaul Durrant * for destruction. Hence add it to the 'inactive' list to be cleaned
5323809f758SPaul Durrant * by xen_bus_cleanup().
533b6af8926SPaul Durrant */
5343809f758SPaul Durrant if (!online &&
5353809f758SPaul Durrant (state == XenbusStateClosed || state == XenbusStateInitialising ||
5363809f758SPaul Durrant state == XenbusStateInitWait || state == XenbusStateUnknown) &&
5373809f758SPaul Durrant !xendev->inactive) {
5383809f758SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
539a783f8adSPaul Durrant
5403809f758SPaul Durrant xendev->inactive = true;
5413809f758SPaul Durrant QLIST_INSERT_HEAD(&xenbus->inactive_devices, xendev, list);
542a783f8adSPaul Durrant
5433809f758SPaul Durrant /*
5443809f758SPaul Durrant * Re-write the state to cause a XenBus backend_watch notification,
5453809f758SPaul Durrant * resulting in a call to xen_bus_cleanup().
5463809f758SPaul Durrant */
5473809f758SPaul Durrant xen_device_backend_printf(xendev, "state", "%u", state);
548a783f8adSPaul Durrant }
549b6af8926SPaul Durrant }
550b6af8926SPaul Durrant
xen_device_backend_create(XenDevice * xendev,Error ** errp)551094a2239SPaul Durrant static void xen_device_backend_create(XenDevice *xendev, Error **errp)
552094a2239SPaul Durrant {
5531de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD();
554094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
555094a2239SPaul Durrant
556094a2239SPaul Durrant xendev->backend_path = xen_device_get_backend_path(xendev);
557094a2239SPaul Durrant
558094a2239SPaul Durrant g_assert(xenbus->xsh);
559094a2239SPaul Durrant
560ba2a92dbSPaul Durrant xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path,
561ba2a92dbSPaul Durrant xenbus->backend_id, xendev->frontend_id, XS_PERM_READ, errp);
5621de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
5631de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to create backend: ");
564b6af8926SPaul Durrant return;
565b6af8926SPaul Durrant }
566b6af8926SPaul Durrant
567b6af8926SPaul Durrant xendev->backend_state_watch =
568ba2a92dbSPaul Durrant xs_node_watch(xendev->xsh, xendev->backend_path,
569ba2a92dbSPaul Durrant "state", xen_device_backend_changed, xendev,
5701de7096dSVladimir Sementsov-Ogievskiy errp);
5711de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
5721de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to watch backend state: ");
573b6af8926SPaul Durrant return;
574b6af8926SPaul Durrant }
575b6af8926SPaul Durrant
576b6af8926SPaul Durrant xendev->backend_online_watch =
577ba2a92dbSPaul Durrant xs_node_watch(xendev->xsh, xendev->backend_path,
578ba2a92dbSPaul Durrant "online", xen_device_backend_changed, xendev,
5791de7096dSVladimir Sementsov-Ogievskiy errp);
5801de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
5811de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to watch backend online: ");
582b6af8926SPaul Durrant return;
583094a2239SPaul Durrant }
584094a2239SPaul Durrant }
585094a2239SPaul Durrant
xen_device_backend_destroy(XenDevice * xendev)586094a2239SPaul Durrant static void xen_device_backend_destroy(XenDevice *xendev)
587094a2239SPaul Durrant {
588094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
589094a2239SPaul Durrant Error *local_err = NULL;
590094a2239SPaul Durrant
591b6af8926SPaul Durrant if (xendev->backend_online_watch) {
592ba2a92dbSPaul Durrant xs_node_unwatch(xendev->xsh, xendev->backend_online_watch);
593b6af8926SPaul Durrant xendev->backend_online_watch = NULL;
594b6af8926SPaul Durrant }
595b6af8926SPaul Durrant
596b6af8926SPaul Durrant if (xendev->backend_state_watch) {
597ba2a92dbSPaul Durrant xs_node_unwatch(xendev->xsh, xendev->backend_state_watch);
598b6af8926SPaul Durrant xendev->backend_state_watch = NULL;
599b6af8926SPaul Durrant }
600b6af8926SPaul Durrant
601094a2239SPaul Durrant if (!xendev->backend_path) {
602094a2239SPaul Durrant return;
603094a2239SPaul Durrant }
604094a2239SPaul Durrant
605094a2239SPaul Durrant g_assert(xenbus->xsh);
606094a2239SPaul Durrant
607094a2239SPaul Durrant xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path,
608094a2239SPaul Durrant &local_err);
609094a2239SPaul Durrant g_free(xendev->backend_path);
610094a2239SPaul Durrant xendev->backend_path = NULL;
611094a2239SPaul Durrant
612094a2239SPaul Durrant if (local_err) {
613094a2239SPaul Durrant error_report_err(local_err);
614094a2239SPaul Durrant }
615094a2239SPaul Durrant }
616094a2239SPaul Durrant
xen_device_frontend_printf(XenDevice * xendev,const char * key,const char * fmt,...)617b6af8926SPaul Durrant void xen_device_frontend_printf(XenDevice *xendev, const char *key,
618094a2239SPaul Durrant const char *fmt, ...)
619094a2239SPaul Durrant {
620094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
621094a2239SPaul Durrant Error *local_err = NULL;
622094a2239SPaul Durrant va_list ap;
623094a2239SPaul Durrant
624094a2239SPaul Durrant g_assert(xenbus->xsh);
625094a2239SPaul Durrant
626094a2239SPaul Durrant va_start(ap, fmt);
627094a2239SPaul Durrant xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
628094a2239SPaul Durrant &local_err, fmt, ap);
629094a2239SPaul Durrant va_end(ap);
630094a2239SPaul Durrant
631094a2239SPaul Durrant if (local_err) {
632094a2239SPaul Durrant error_report_err(local_err);
633094a2239SPaul Durrant }
634094a2239SPaul Durrant }
635094a2239SPaul Durrant
xen_device_frontend_scanf(XenDevice * xendev,const char * key,const char * fmt,...)636b6af8926SPaul Durrant int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
63782a29e30SPaul Durrant const char *fmt, ...)
63882a29e30SPaul Durrant {
63982a29e30SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
64082a29e30SPaul Durrant va_list ap;
64182a29e30SPaul Durrant int rc;
64282a29e30SPaul Durrant
64382a29e30SPaul Durrant g_assert(xenbus->xsh);
64482a29e30SPaul Durrant
64582a29e30SPaul Durrant va_start(ap, fmt);
64682a29e30SPaul Durrant rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
64782a29e30SPaul Durrant NULL, fmt, ap);
64882a29e30SPaul Durrant va_end(ap);
64982a29e30SPaul Durrant
65082a29e30SPaul Durrant return rc;
65182a29e30SPaul Durrant }
65282a29e30SPaul Durrant
xen_device_frontend_set_state(XenDevice * xendev,enum xenbus_state state,bool publish)653094a2239SPaul Durrant static void xen_device_frontend_set_state(XenDevice *xendev,
654705be570SAnthony PERARD enum xenbus_state state,
655705be570SAnthony PERARD bool publish)
656094a2239SPaul Durrant {
657094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
658094a2239SPaul Durrant
659094a2239SPaul Durrant if (xendev->frontend_state == state) {
660094a2239SPaul Durrant return;
661094a2239SPaul Durrant }
662094a2239SPaul Durrant
663094a2239SPaul Durrant trace_xen_device_frontend_state(type, xendev->name,
664094a2239SPaul Durrant xs_strstate(state));
665094a2239SPaul Durrant
666094a2239SPaul Durrant xendev->frontend_state = state;
667705be570SAnthony PERARD if (publish) {
668094a2239SPaul Durrant xen_device_frontend_printf(xendev, "state", "%u", state);
669094a2239SPaul Durrant }
670705be570SAnthony PERARD }
671094a2239SPaul Durrant
xen_device_frontend_changed(void * opaque,const char * path)672ba2a92dbSPaul Durrant static void xen_device_frontend_changed(void *opaque, const char *path)
67382a29e30SPaul Durrant {
67482a29e30SPaul Durrant XenDevice *xendev = opaque;
67582a29e30SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
67682a29e30SPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
67782a29e30SPaul Durrant enum xenbus_state state;
67882a29e30SPaul Durrant
67982a29e30SPaul Durrant trace_xen_device_frontend_changed(type, xendev->name);
68082a29e30SPaul Durrant
68182a29e30SPaul Durrant if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) {
68282a29e30SPaul Durrant state = XenbusStateUnknown;
68382a29e30SPaul Durrant }
68482a29e30SPaul Durrant
685705be570SAnthony PERARD xen_device_frontend_set_state(xendev, state, false);
68682a29e30SPaul Durrant
68767bc8e00SPaul Durrant if (state == XenbusStateInitialising &&
68867bc8e00SPaul Durrant xendev->backend_state == XenbusStateClosed &&
68967bc8e00SPaul Durrant xendev->backend_online) {
69067bc8e00SPaul Durrant /*
69167bc8e00SPaul Durrant * The frontend is re-initializing so switch back to
69267bc8e00SPaul Durrant * InitWait.
69367bc8e00SPaul Durrant */
69467bc8e00SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateInitWait);
69567bc8e00SPaul Durrant return;
69667bc8e00SPaul Durrant }
69767bc8e00SPaul Durrant
69882a29e30SPaul Durrant if (xendev_class->frontend_changed) {
69982a29e30SPaul Durrant Error *local_err = NULL;
70082a29e30SPaul Durrant
70182a29e30SPaul Durrant xendev_class->frontend_changed(xendev, state, &local_err);
70282a29e30SPaul Durrant
70382a29e30SPaul Durrant if (local_err) {
70482a29e30SPaul Durrant error_reportf_err(local_err, "frontend change error: ");
70582a29e30SPaul Durrant }
70682a29e30SPaul Durrant }
70782a29e30SPaul Durrant }
70882a29e30SPaul Durrant
xen_device_frontend_exists(XenDevice * xendev)7096bd6b955SMark Syms static bool xen_device_frontend_exists(XenDevice *xendev)
7106bd6b955SMark Syms {
7116bd6b955SMark Syms enum xenbus_state state;
7126bd6b955SMark Syms
7136bd6b955SMark Syms return (xen_device_frontend_scanf(xendev, "state", "%u", &state) == 1);
7146bd6b955SMark Syms }
7156bd6b955SMark Syms
xen_device_frontend_create(XenDevice * xendev,Error ** errp)716094a2239SPaul Durrant static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
717094a2239SPaul Durrant {
7181de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD();
719094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
720523b6b3aSDavid Woodhouse XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
721094a2239SPaul Durrant
722523b6b3aSDavid Woodhouse if (xendev_class->get_frontend_path) {
723523b6b3aSDavid Woodhouse xendev->frontend_path = xendev_class->get_frontend_path(xendev, errp);
724523b6b3aSDavid Woodhouse if (!xendev->frontend_path) {
725523b6b3aSDavid Woodhouse error_prepend(errp, "failed to create frontend: ");
726523b6b3aSDavid Woodhouse return;
727523b6b3aSDavid Woodhouse }
728523b6b3aSDavid Woodhouse } else {
729094a2239SPaul Durrant xendev->frontend_path = xen_device_get_frontend_path(xendev);
730523b6b3aSDavid Woodhouse }
731094a2239SPaul Durrant
7326bd6b955SMark Syms /*
7336bd6b955SMark Syms * The frontend area may have already been created by a legacy
7346bd6b955SMark Syms * toolstack.
7356bd6b955SMark Syms */
7366bd6b955SMark Syms if (!xen_device_frontend_exists(xendev)) {
737094a2239SPaul Durrant g_assert(xenbus->xsh);
738094a2239SPaul Durrant
739ba2a92dbSPaul Durrant xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path,
740ba2a92dbSPaul Durrant xendev->frontend_id, xenbus->backend_id,
741ba2a92dbSPaul Durrant XS_PERM_READ | XS_PERM_WRITE, errp);
7421de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
7431de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to create frontend: ");
74482a29e30SPaul Durrant return;
74582a29e30SPaul Durrant }
7466bd6b955SMark Syms }
74782a29e30SPaul Durrant
74882a29e30SPaul Durrant xendev->frontend_state_watch =
749ba2a92dbSPaul Durrant xs_node_watch(xendev->xsh, xendev->frontend_path, "state",
750ba2a92dbSPaul Durrant xen_device_frontend_changed, xendev, errp);
7511de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
7521de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to watch frontend state: ");
753094a2239SPaul Durrant }
754094a2239SPaul Durrant }
755094a2239SPaul Durrant
xen_device_frontend_destroy(XenDevice * xendev)756094a2239SPaul Durrant static void xen_device_frontend_destroy(XenDevice *xendev)
757094a2239SPaul Durrant {
758094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
759094a2239SPaul Durrant Error *local_err = NULL;
760094a2239SPaul Durrant
76182a29e30SPaul Durrant if (xendev->frontend_state_watch) {
762ba2a92dbSPaul Durrant xs_node_unwatch(xendev->xsh, xendev->frontend_state_watch);
76382a29e30SPaul Durrant xendev->frontend_state_watch = NULL;
76482a29e30SPaul Durrant }
76582a29e30SPaul Durrant
766094a2239SPaul Durrant if (!xendev->frontend_path) {
767094a2239SPaul Durrant return;
768094a2239SPaul Durrant }
769094a2239SPaul Durrant
770094a2239SPaul Durrant g_assert(xenbus->xsh);
771094a2239SPaul Durrant
772094a2239SPaul Durrant xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path,
773094a2239SPaul Durrant &local_err);
774094a2239SPaul Durrant g_free(xendev->frontend_path);
775094a2239SPaul Durrant xendev->frontend_path = NULL;
776094a2239SPaul Durrant
777094a2239SPaul Durrant if (local_err) {
778094a2239SPaul Durrant error_report_err(local_err);
779094a2239SPaul Durrant }
780094a2239SPaul Durrant }
781094a2239SPaul Durrant
xen_device_set_max_grant_refs(XenDevice * xendev,unsigned int nr_refs,Error ** errp)7824b34b5b1SPaul Durrant void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
7834b34b5b1SPaul Durrant Error **errp)
7844b34b5b1SPaul Durrant {
785c412ba47SDavid Woodhouse if (qemu_xen_gnttab_set_max_grants(xendev->xgth, nr_refs)) {
7864b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_set_max_grants failed");
7874b34b5b1SPaul Durrant }
7884b34b5b1SPaul Durrant }
7894b34b5b1SPaul Durrant
xen_device_map_grant_refs(XenDevice * xendev,uint32_t * refs,unsigned int nr_refs,int prot,Error ** errp)7904b34b5b1SPaul Durrant void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
7914b34b5b1SPaul Durrant unsigned int nr_refs, int prot,
7924b34b5b1SPaul Durrant Error **errp)
7934b34b5b1SPaul Durrant {
794c412ba47SDavid Woodhouse void *map = qemu_xen_gnttab_map_refs(xendev->xgth, nr_refs,
795c412ba47SDavid Woodhouse xendev->frontend_id, refs, prot);
7964b34b5b1SPaul Durrant
7974b34b5b1SPaul Durrant if (!map) {
7984b34b5b1SPaul Durrant error_setg_errno(errp, errno,
7994b34b5b1SPaul Durrant "xengnttab_map_domain_grant_refs failed");
8004b34b5b1SPaul Durrant }
8014b34b5b1SPaul Durrant
8024b34b5b1SPaul Durrant return map;
8034b34b5b1SPaul Durrant }
8044b34b5b1SPaul Durrant
xen_device_unmap_grant_refs(XenDevice * xendev,void * map,uint32_t * refs,unsigned int nr_refs,Error ** errp)805f80fad16SDavid Woodhouse void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, uint32_t *refs,
8064b34b5b1SPaul Durrant unsigned int nr_refs, Error **errp)
8074b34b5b1SPaul Durrant {
808f80fad16SDavid Woodhouse if (qemu_xen_gnttab_unmap(xendev->xgth, map, refs, nr_refs)) {
8094b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_unmap failed");
8104b34b5b1SPaul Durrant }
8114b34b5b1SPaul Durrant }
8124b34b5b1SPaul Durrant
xen_device_copy_grant_refs(XenDevice * xendev,bool to_domain,XenDeviceGrantCopySegment segs[],unsigned int nr_segs,Error ** errp)8134b34b5b1SPaul Durrant void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
8144b34b5b1SPaul Durrant XenDeviceGrantCopySegment segs[],
8154b34b5b1SPaul Durrant unsigned int nr_segs, Error **errp)
8164b34b5b1SPaul Durrant {
817c412ba47SDavid Woodhouse qemu_xen_gnttab_grant_copy(xendev->xgth, to_domain, xendev->frontend_id,
818c412ba47SDavid Woodhouse (XenGrantCopySegment *)segs, nr_segs, errp);
8194b34b5b1SPaul Durrant }
8204b34b5b1SPaul Durrant
821a3d669c8SPaul Durrant struct XenEventChannel {
822c0b336eaSPaul Durrant QLIST_ENTRY(XenEventChannel) list;
82383361a8aSPaul Durrant AioContext *ctx;
824c0b336eaSPaul Durrant xenevtchn_handle *xeh;
825a3d669c8SPaul Durrant evtchn_port_t local_port;
826a3d669c8SPaul Durrant XenEventHandler handler;
827a3d669c8SPaul Durrant void *opaque;
828a3d669c8SPaul Durrant };
829a3d669c8SPaul Durrant
xen_device_poll(void * opaque)830345f42b4SPaul Durrant static bool xen_device_poll(void *opaque)
831345f42b4SPaul Durrant {
832345f42b4SPaul Durrant XenEventChannel *channel = opaque;
833345f42b4SPaul Durrant
834345f42b4SPaul Durrant return channel->handler(channel->opaque);
835345f42b4SPaul Durrant }
836345f42b4SPaul Durrant
xen_device_event(void * opaque)837c0b336eaSPaul Durrant static void xen_device_event(void *opaque)
838a3d669c8SPaul Durrant {
839c0b336eaSPaul Durrant XenEventChannel *channel = opaque;
840b6cacfeaSDavid Woodhouse unsigned long port = qemu_xen_evtchn_pending(channel->xeh);
841a3d669c8SPaul Durrant
842a3d669c8SPaul Durrant if (port == channel->local_port) {
843345f42b4SPaul Durrant xen_device_poll(channel);
844c0b336eaSPaul Durrant
845b6cacfeaSDavid Woodhouse qemu_xen_evtchn_unmask(channel->xeh, port);
846a3d669c8SPaul Durrant }
847a3d669c8SPaul Durrant }
848a3d669c8SPaul Durrant
xen_device_set_event_channel_context(XenDevice * xendev,XenEventChannel * channel,AioContext * ctx,Error ** errp)84932d0b7beSPaul Durrant void xen_device_set_event_channel_context(XenDevice *xendev,
85032d0b7beSPaul Durrant XenEventChannel *channel,
85183361a8aSPaul Durrant AioContext *ctx,
85232d0b7beSPaul Durrant Error **errp)
85332d0b7beSPaul Durrant {
85432d0b7beSPaul Durrant if (!channel) {
85532d0b7beSPaul Durrant error_setg(errp, "bad channel");
85632d0b7beSPaul Durrant return;
85732d0b7beSPaul Durrant }
85832d0b7beSPaul Durrant
85932d0b7beSPaul Durrant if (channel->ctx)
86060f782b6SStefan Hajnoczi aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh),
861826cc324SStefan Hajnoczi NULL, NULL, NULL, NULL, NULL);
86232d0b7beSPaul Durrant
86332d0b7beSPaul Durrant channel->ctx = ctx;
864f6eac904SStefan Hajnoczi if (ctx) {
865f6eac904SStefan Hajnoczi aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh),
86660f782b6SStefan Hajnoczi xen_device_event, NULL, xen_device_poll, NULL,
86760f782b6SStefan Hajnoczi channel);
868f6eac904SStefan Hajnoczi }
86932d0b7beSPaul Durrant }
87032d0b7beSPaul Durrant
xen_device_bind_event_channel(XenDevice * xendev,unsigned int port,XenEventHandler handler,void * opaque,Error ** errp)87132d0b7beSPaul Durrant XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
872a3d669c8SPaul Durrant unsigned int port,
873a3d669c8SPaul Durrant XenEventHandler handler,
874a3d669c8SPaul Durrant void *opaque, Error **errp)
875a3d669c8SPaul Durrant {
876a3d669c8SPaul Durrant XenEventChannel *channel = g_new0(XenEventChannel, 1);
877a3d669c8SPaul Durrant xenevtchn_port_or_error_t local_port;
878a3d669c8SPaul Durrant
879b6cacfeaSDavid Woodhouse channel->xeh = qemu_xen_evtchn_open();
880c0b336eaSPaul Durrant if (!channel->xeh) {
881c0b336eaSPaul Durrant error_setg_errno(errp, errno, "failed xenevtchn_open");
882c0b336eaSPaul Durrant goto fail;
883c0b336eaSPaul Durrant }
884c0b336eaSPaul Durrant
885b6cacfeaSDavid Woodhouse local_port = qemu_xen_evtchn_bind_interdomain(channel->xeh,
886a3d669c8SPaul Durrant xendev->frontend_id,
887a3d669c8SPaul Durrant port);
888a3d669c8SPaul Durrant if (local_port < 0) {
889a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed");
890c0b336eaSPaul Durrant goto fail;
891a3d669c8SPaul Durrant }
892a3d669c8SPaul Durrant
893a3d669c8SPaul Durrant channel->local_port = local_port;
894a3d669c8SPaul Durrant channel->handler = handler;
895a3d669c8SPaul Durrant channel->opaque = opaque;
896a3d669c8SPaul Durrant
89732d0b7beSPaul Durrant /* Only reason for failure is a NULL channel */
89832d0b7beSPaul Durrant xen_device_set_event_channel_context(xendev, channel,
89932d0b7beSPaul Durrant qemu_get_aio_context(),
90032d0b7beSPaul Durrant &error_abort);
901c0b336eaSPaul Durrant
902c0b336eaSPaul Durrant QLIST_INSERT_HEAD(&xendev->event_channels, channel, list);
903a3d669c8SPaul Durrant
904a3d669c8SPaul Durrant return channel;
905c0b336eaSPaul Durrant
906c0b336eaSPaul Durrant fail:
907c0b336eaSPaul Durrant if (channel->xeh) {
908b6cacfeaSDavid Woodhouse qemu_xen_evtchn_close(channel->xeh);
909c0b336eaSPaul Durrant }
910c0b336eaSPaul Durrant
911c0b336eaSPaul Durrant g_free(channel);
912c0b336eaSPaul Durrant
913c0b336eaSPaul Durrant return NULL;
914a3d669c8SPaul Durrant }
915a3d669c8SPaul Durrant
xen_device_notify_event_channel(XenDevice * xendev,XenEventChannel * channel,Error ** errp)916a3d669c8SPaul Durrant void xen_device_notify_event_channel(XenDevice *xendev,
917a3d669c8SPaul Durrant XenEventChannel *channel,
918a3d669c8SPaul Durrant Error **errp)
919a3d669c8SPaul Durrant {
920a3d669c8SPaul Durrant if (!channel) {
921a3d669c8SPaul Durrant error_setg(errp, "bad channel");
922a3d669c8SPaul Durrant return;
923a3d669c8SPaul Durrant }
924a3d669c8SPaul Durrant
925b6cacfeaSDavid Woodhouse if (qemu_xen_evtchn_notify(channel->xeh, channel->local_port) < 0) {
926a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_notify failed");
927a3d669c8SPaul Durrant }
928a3d669c8SPaul Durrant }
929a3d669c8SPaul Durrant
xen_event_channel_get_local_port(XenEventChannel * channel)930a72ccc7fSDavid Woodhouse unsigned int xen_event_channel_get_local_port(XenEventChannel *channel)
931a72ccc7fSDavid Woodhouse {
932a72ccc7fSDavid Woodhouse return channel->local_port;
933a72ccc7fSDavid Woodhouse }
934a72ccc7fSDavid Woodhouse
xen_device_unbind_event_channel(XenDevice * xendev,XenEventChannel * channel,Error ** errp)935a3d669c8SPaul Durrant void xen_device_unbind_event_channel(XenDevice *xendev,
936a3d669c8SPaul Durrant XenEventChannel *channel,
937a3d669c8SPaul Durrant Error **errp)
938a3d669c8SPaul Durrant {
939a3d669c8SPaul Durrant if (!channel) {
940a3d669c8SPaul Durrant error_setg(errp, "bad channel");
941a3d669c8SPaul Durrant return;
942a3d669c8SPaul Durrant }
943a3d669c8SPaul Durrant
944c0b336eaSPaul Durrant QLIST_REMOVE(channel, list);
945a3d669c8SPaul Durrant
94690006660SAnthony PERARD if (channel->ctx) {
94760f782b6SStefan Hajnoczi aio_set_fd_handler(channel->ctx, qemu_xen_evtchn_fd(channel->xeh),
948826cc324SStefan Hajnoczi NULL, NULL, NULL, NULL, NULL);
94990006660SAnthony PERARD }
950c0b336eaSPaul Durrant
951b6cacfeaSDavid Woodhouse if (qemu_xen_evtchn_unbind(channel->xeh, channel->local_port) < 0) {
952a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_unbind failed");
953a3d669c8SPaul Durrant }
954a3d669c8SPaul Durrant
955b6cacfeaSDavid Woodhouse qemu_xen_evtchn_close(channel->xeh);
956a3d669c8SPaul Durrant g_free(channel);
957a3d669c8SPaul Durrant }
958a3d669c8SPaul Durrant
xen_device_unrealize(DeviceState * dev)959b69c3c21SMarkus Armbruster static void xen_device_unrealize(DeviceState *dev)
960108f7bbaSPaul Durrant {
961108f7bbaSPaul Durrant XenDevice *xendev = XEN_DEVICE(dev);
962108f7bbaSPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
963108f7bbaSPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
964c0b336eaSPaul Durrant XenEventChannel *channel, *next;
965108f7bbaSPaul Durrant
966094a2239SPaul Durrant if (!xendev->name) {
967094a2239SPaul Durrant return;
968094a2239SPaul Durrant }
969094a2239SPaul Durrant
970094a2239SPaul Durrant trace_xen_device_unrealize(type, xendev->name);
971094a2239SPaul Durrant
972094a2239SPaul Durrant if (xendev->exit.notify) {
973094a2239SPaul Durrant qemu_remove_exit_notifier(&xendev->exit);
974094a2239SPaul Durrant xendev->exit.notify = NULL;
975094a2239SPaul Durrant }
976108f7bbaSPaul Durrant
977108f7bbaSPaul Durrant if (xendev_class->unrealize) {
978b69c3c21SMarkus Armbruster xendev_class->unrealize(xendev);
979108f7bbaSPaul Durrant }
980094a2239SPaul Durrant
981c0b336eaSPaul Durrant /* Make sure all event channels are cleaned up */
982c0b336eaSPaul Durrant QLIST_FOREACH_SAFE(channel, &xendev->event_channels, list, next) {
983c0b336eaSPaul Durrant xen_device_unbind_event_channel(xendev, channel, NULL);
984c0b336eaSPaul Durrant }
985c0b336eaSPaul Durrant
986094a2239SPaul Durrant xen_device_frontend_destroy(xendev);
987094a2239SPaul Durrant xen_device_backend_destroy(xendev);
988094a2239SPaul Durrant
9894b34b5b1SPaul Durrant if (xendev->xgth) {
990c412ba47SDavid Woodhouse qemu_xen_gnttab_close(xendev->xgth);
9914b34b5b1SPaul Durrant xendev->xgth = NULL;
9924b34b5b1SPaul Durrant }
9934b34b5b1SPaul Durrant
994d198b711SPaul Durrant if (xendev->xsh) {
995ba2a92dbSPaul Durrant qemu_xen_xs_close(xendev->xsh);
996d198b711SPaul Durrant xendev->xsh = NULL;
997d198b711SPaul Durrant }
998d198b711SPaul Durrant
999094a2239SPaul Durrant g_free(xendev->name);
1000094a2239SPaul Durrant xendev->name = NULL;
1001094a2239SPaul Durrant }
1002094a2239SPaul Durrant
xen_device_exit(Notifier * n,void * data)1003094a2239SPaul Durrant static void xen_device_exit(Notifier *n, void *data)
1004094a2239SPaul Durrant {
1005094a2239SPaul Durrant XenDevice *xendev = container_of(n, XenDevice, exit);
1006094a2239SPaul Durrant
1007b69c3c21SMarkus Armbruster xen_device_unrealize(DEVICE(xendev));
1008108f7bbaSPaul Durrant }
1009108f7bbaSPaul Durrant
xen_device_realize(DeviceState * dev,Error ** errp)1010108f7bbaSPaul Durrant static void xen_device_realize(DeviceState *dev, Error **errp)
1011108f7bbaSPaul Durrant {
10121de7096dSVladimir Sementsov-Ogievskiy ERRP_GUARD();
1013108f7bbaSPaul Durrant XenDevice *xendev = XEN_DEVICE(dev);
1014108f7bbaSPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
1015094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
1016108f7bbaSPaul Durrant const char *type = object_get_typename(OBJECT(xendev));
1017108f7bbaSPaul Durrant
1018094a2239SPaul Durrant if (xendev->frontend_id == DOMID_INVALID) {
1019094a2239SPaul Durrant xendev->frontend_id = xen_domid;
1020094a2239SPaul Durrant }
1021094a2239SPaul Durrant
1022094a2239SPaul Durrant if (xendev->frontend_id >= DOMID_FIRST_RESERVED) {
1023094a2239SPaul Durrant error_setg(errp, "invalid frontend-id");
1024094a2239SPaul Durrant goto unrealize;
1025094a2239SPaul Durrant }
1026094a2239SPaul Durrant
1027094a2239SPaul Durrant if (!xendev_class->get_name) {
1028094a2239SPaul Durrant error_setg(errp, "get_name method not implemented");
1029094a2239SPaul Durrant goto unrealize;
1030094a2239SPaul Durrant }
1031094a2239SPaul Durrant
10321de7096dSVladimir Sementsov-Ogievskiy xendev->name = xendev_class->get_name(xendev, errp);
10331de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
10341de7096dSVladimir Sementsov-Ogievskiy error_prepend(errp, "failed to get device name: ");
1035094a2239SPaul Durrant goto unrealize;
1036094a2239SPaul Durrant }
1037094a2239SPaul Durrant
1038094a2239SPaul Durrant trace_xen_device_realize(type, xendev->name);
1039094a2239SPaul Durrant
1040ba2a92dbSPaul Durrant xendev->xsh = qemu_xen_xs_open();
1041d198b711SPaul Durrant if (!xendev->xsh) {
1042d198b711SPaul Durrant error_setg_errno(errp, errno, "failed xs_open");
1043d198b711SPaul Durrant goto unrealize;
1044d198b711SPaul Durrant }
1045d198b711SPaul Durrant
1046c412ba47SDavid Woodhouse xendev->xgth = qemu_xen_gnttab_open();
10474b34b5b1SPaul Durrant if (!xendev->xgth) {
10484b34b5b1SPaul Durrant error_setg_errno(errp, errno, "failed xengnttab_open");
10494b34b5b1SPaul Durrant goto unrealize;
10504b34b5b1SPaul Durrant }
10514b34b5b1SPaul Durrant
10521de7096dSVladimir Sementsov-Ogievskiy xen_device_backend_create(xendev, errp);
10531de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
1054094a2239SPaul Durrant goto unrealize;
1055094a2239SPaul Durrant }
1056094a2239SPaul Durrant
10571de7096dSVladimir Sementsov-Ogievskiy xen_device_frontend_create(xendev, errp);
10581de7096dSVladimir Sementsov-Ogievskiy if (*errp) {
1059094a2239SPaul Durrant goto unrealize;
1060094a2239SPaul Durrant }
1061108f7bbaSPaul Durrant
1062094a2239SPaul Durrant xen_device_backend_printf(xendev, "frontend", "%s",
1063094a2239SPaul Durrant xendev->frontend_path);
1064094a2239SPaul Durrant xen_device_backend_printf(xendev, "frontend-id", "%u",
1065094a2239SPaul Durrant xendev->frontend_id);
1066094a2239SPaul Durrant xen_device_backend_printf(xendev, "hotplug-status", "connected");
1067094a2239SPaul Durrant
1068b6af8926SPaul Durrant xen_device_backend_set_online(xendev, true);
1069094a2239SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateInitWait);
1070094a2239SPaul Durrant
10716bd6b955SMark Syms if (!xen_device_frontend_exists(xendev)) {
1072094a2239SPaul Durrant xen_device_frontend_printf(xendev, "backend", "%s",
1073094a2239SPaul Durrant xendev->backend_path);
1074094a2239SPaul Durrant xen_device_frontend_printf(xendev, "backend-id", "%u",
1075094a2239SPaul Durrant xenbus->backend_id);
1076094a2239SPaul Durrant
1077705be570SAnthony PERARD xen_device_frontend_set_state(xendev, XenbusStateInitialising, true);
10786bd6b955SMark Syms }
1079094a2239SPaul Durrant
1080240cc113SPaul Durrant if (xendev_class->realize) {
1081240cc113SPaul Durrant xendev_class->realize(xendev, errp);
1082240cc113SPaul Durrant if (*errp) {
1083240cc113SPaul Durrant goto unrealize;
1084240cc113SPaul Durrant }
1085240cc113SPaul Durrant }
1086240cc113SPaul Durrant
1087094a2239SPaul Durrant xendev->exit.notify = xen_device_exit;
1088094a2239SPaul Durrant qemu_add_exit_notifier(&xendev->exit);
1089108f7bbaSPaul Durrant return;
1090108f7bbaSPaul Durrant
1091108f7bbaSPaul Durrant unrealize:
1092b69c3c21SMarkus Armbruster xen_device_unrealize(dev);
1093108f7bbaSPaul Durrant }
1094108f7bbaSPaul Durrant
1095094a2239SPaul Durrant static Property xen_device_props[] = {
1096094a2239SPaul Durrant DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
1097094a2239SPaul Durrant DOMID_INVALID),
1098094a2239SPaul Durrant DEFINE_PROP_END_OF_LIST()
1099094a2239SPaul Durrant };
1100094a2239SPaul Durrant
xen_device_class_init(ObjectClass * class,void * data)1101108f7bbaSPaul Durrant static void xen_device_class_init(ObjectClass *class, void *data)
1102108f7bbaSPaul Durrant {
1103108f7bbaSPaul Durrant DeviceClass *dev_class = DEVICE_CLASS(class);
1104108f7bbaSPaul Durrant
1105108f7bbaSPaul Durrant dev_class->realize = xen_device_realize;
1106108f7bbaSPaul Durrant dev_class->unrealize = xen_device_unrealize;
11074f67d30bSMarc-André Lureau device_class_set_props(dev_class, xen_device_props);
1108108f7bbaSPaul Durrant dev_class->bus_type = TYPE_XEN_BUS;
1109108f7bbaSPaul Durrant }
1110108f7bbaSPaul Durrant
1111108f7bbaSPaul Durrant static const TypeInfo xen_device_type_info = {
1112108f7bbaSPaul Durrant .name = TYPE_XEN_DEVICE,
1113108f7bbaSPaul Durrant .parent = TYPE_DEVICE,
1114108f7bbaSPaul Durrant .instance_size = sizeof(XenDevice),
1115108f7bbaSPaul Durrant .abstract = true,
1116108f7bbaSPaul Durrant .class_size = sizeof(XenDeviceClass),
1117108f7bbaSPaul Durrant .class_init = xen_device_class_init,
1118108f7bbaSPaul Durrant };
1119108f7bbaSPaul Durrant
1120108f7bbaSPaul Durrant typedef struct XenBridge {
1121108f7bbaSPaul Durrant SysBusDevice busdev;
1122108f7bbaSPaul Durrant } XenBridge;
1123108f7bbaSPaul Durrant
1124108f7bbaSPaul Durrant #define TYPE_XEN_BRIDGE "xen-bridge"
1125108f7bbaSPaul Durrant
1126108f7bbaSPaul Durrant static const TypeInfo xen_bridge_type_info = {
1127108f7bbaSPaul Durrant .name = TYPE_XEN_BRIDGE,
1128108f7bbaSPaul Durrant .parent = TYPE_SYS_BUS_DEVICE,
1129108f7bbaSPaul Durrant .instance_size = sizeof(XenBridge),
1130108f7bbaSPaul Durrant };
1131108f7bbaSPaul Durrant
xen_register_types(void)1132108f7bbaSPaul Durrant static void xen_register_types(void)
1133108f7bbaSPaul Durrant {
1134108f7bbaSPaul Durrant type_register_static(&xen_bridge_type_info);
1135108f7bbaSPaul Durrant type_register_static(&xen_bus_type_info);
1136108f7bbaSPaul Durrant type_register_static(&xen_device_type_info);
1137108f7bbaSPaul Durrant }
1138108f7bbaSPaul Durrant
type_init(xen_register_types)1139108f7bbaSPaul Durrant type_init(xen_register_types)
1140108f7bbaSPaul Durrant
11417d6eff13SDavid Woodhouse void xen_bus_init(void)
1142108f7bbaSPaul Durrant {
11433e80f690SMarkus Armbruster DeviceState *dev = qdev_new(TYPE_XEN_BRIDGE);
11449388d170SPeter Maydell BusState *bus = qbus_new(TYPE_XEN_BUS, dev, NULL);
1145108f7bbaSPaul Durrant
11463c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
1147cd7c8660SMarkus Armbruster qbus_set_bus_hotplug_handler(bus);
1148c10b4b3cSDavid Woodhouse
11497d6eff13SDavid Woodhouse qemu_create_nic_bus_devices(bus, TYPE_XEN_DEVICE, "xen-net-device",
11507d6eff13SDavid Woodhouse "xen", "xen-net-device");
1151108f7bbaSPaul Durrant }
1152