xref: /openbmc/qemu/hw/xen/xen-bus.c (revision 4b34b5b14054edded15888448b0aad3723b99c29)
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"
1082a29e30SPaul Durrant #include "qemu/uuid.h"
11108f7bbaSPaul Durrant #include "hw/hw.h"
12108f7bbaSPaul Durrant #include "hw/sysbus.h"
13094a2239SPaul Durrant #include "hw/xen/xen.h"
14108f7bbaSPaul Durrant #include "hw/xen/xen-bus.h"
15094a2239SPaul Durrant #include "hw/xen/xen-bus-helper.h"
16094a2239SPaul Durrant #include "monitor/monitor.h"
17108f7bbaSPaul Durrant #include "qapi/error.h"
18094a2239SPaul Durrant #include "sysemu/sysemu.h"
19108f7bbaSPaul Durrant #include "trace.h"
20108f7bbaSPaul Durrant 
21094a2239SPaul Durrant static char *xen_device_get_backend_path(XenDevice *xendev)
22094a2239SPaul Durrant {
23094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
24094a2239SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
25094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
26094a2239SPaul Durrant     const char *backend = xendev_class->backend;
27094a2239SPaul Durrant 
28094a2239SPaul Durrant     if (!backend) {
29094a2239SPaul Durrant         backend = type;
30094a2239SPaul Durrant     }
31094a2239SPaul Durrant 
32094a2239SPaul Durrant     return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s",
33094a2239SPaul Durrant                            xenbus->backend_id, backend, xendev->frontend_id,
34094a2239SPaul Durrant                            xendev->name);
35094a2239SPaul Durrant }
36094a2239SPaul Durrant 
37094a2239SPaul Durrant static char *xen_device_get_frontend_path(XenDevice *xendev)
38094a2239SPaul Durrant {
39094a2239SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
40094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
41094a2239SPaul Durrant     const char *device = xendev_class->device;
42094a2239SPaul Durrant 
43094a2239SPaul Durrant     if (!device) {
44094a2239SPaul Durrant         device = type;
45094a2239SPaul Durrant     }
46094a2239SPaul Durrant 
47094a2239SPaul Durrant     return g_strdup_printf("/local/domain/%u/device/%s/%s",
48094a2239SPaul Durrant                            xendev->frontend_id, device, xendev->name);
49094a2239SPaul Durrant }
50094a2239SPaul Durrant 
51094a2239SPaul Durrant static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent)
52094a2239SPaul Durrant {
53094a2239SPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
54094a2239SPaul Durrant 
55094a2239SPaul Durrant     monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n",
56094a2239SPaul Durrant                    indent, "", xendev->name, xendev->frontend_id);
57094a2239SPaul Durrant }
58094a2239SPaul Durrant 
59094a2239SPaul Durrant static char *xen_bus_get_dev_path(DeviceState *dev)
60094a2239SPaul Durrant {
61094a2239SPaul Durrant     return xen_device_get_backend_path(XEN_DEVICE(dev));
62094a2239SPaul Durrant }
63094a2239SPaul Durrant 
6482a29e30SPaul Durrant struct XenWatch {
6582a29e30SPaul Durrant     char *node, *key;
6682a29e30SPaul Durrant     char *token;
6782a29e30SPaul Durrant     XenWatchHandler handler;
6882a29e30SPaul Durrant     void *opaque;
6982a29e30SPaul Durrant     Notifier notifier;
7082a29e30SPaul Durrant };
7182a29e30SPaul Durrant 
7282a29e30SPaul Durrant static void watch_notify(Notifier *n, void *data)
7382a29e30SPaul Durrant {
7482a29e30SPaul Durrant     XenWatch *watch = container_of(n, XenWatch, notifier);
7582a29e30SPaul Durrant     const char *token = data;
7682a29e30SPaul Durrant 
7782a29e30SPaul Durrant     if (!strcmp(watch->token, token)) {
7882a29e30SPaul Durrant         watch->handler(watch->opaque);
7982a29e30SPaul Durrant     }
8082a29e30SPaul Durrant }
8182a29e30SPaul Durrant 
8282a29e30SPaul Durrant static XenWatch *new_watch(const char *node, const char *key,
8382a29e30SPaul Durrant                            XenWatchHandler handler, void *opaque)
8482a29e30SPaul Durrant {
8582a29e30SPaul Durrant     XenWatch *watch = g_new0(XenWatch, 1);
8682a29e30SPaul Durrant     QemuUUID uuid;
8782a29e30SPaul Durrant 
8882a29e30SPaul Durrant     qemu_uuid_generate(&uuid);
8982a29e30SPaul Durrant 
9082a29e30SPaul Durrant     watch->token = qemu_uuid_unparse_strdup(&uuid);
9182a29e30SPaul Durrant     watch->node = g_strdup(node);
9282a29e30SPaul Durrant     watch->key = g_strdup(key);
9382a29e30SPaul Durrant     watch->handler = handler;
9482a29e30SPaul Durrant     watch->opaque = opaque;
9582a29e30SPaul Durrant     watch->notifier.notify = watch_notify;
9682a29e30SPaul Durrant 
9782a29e30SPaul Durrant     return watch;
9882a29e30SPaul Durrant }
9982a29e30SPaul Durrant 
10082a29e30SPaul Durrant static void free_watch(XenWatch *watch)
10182a29e30SPaul Durrant {
10282a29e30SPaul Durrant     g_free(watch->token);
10382a29e30SPaul Durrant     g_free(watch->key);
10482a29e30SPaul Durrant     g_free(watch->node);
10582a29e30SPaul Durrant 
10682a29e30SPaul Durrant     g_free(watch);
10782a29e30SPaul Durrant }
10882a29e30SPaul Durrant 
10982a29e30SPaul Durrant static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node,
11082a29e30SPaul Durrant                                    const char *key, XenWatchHandler handler,
11182a29e30SPaul Durrant                                    void *opaque, Error **errp)
11282a29e30SPaul Durrant {
11382a29e30SPaul Durrant     XenWatch *watch = new_watch(node, key, handler, opaque);
11482a29e30SPaul Durrant     Error *local_err = NULL;
11582a29e30SPaul Durrant 
11682a29e30SPaul Durrant     trace_xen_bus_add_watch(watch->node, watch->key, watch->token);
11782a29e30SPaul Durrant 
11882a29e30SPaul Durrant     notifier_list_add(&xenbus->watch_notifiers, &watch->notifier);
11982a29e30SPaul Durrant 
12082a29e30SPaul Durrant     xs_node_watch(xenbus->xsh, node, key, watch->token, &local_err);
12182a29e30SPaul Durrant     if (local_err) {
12282a29e30SPaul Durrant         error_propagate(errp, local_err);
12382a29e30SPaul Durrant 
12482a29e30SPaul Durrant         notifier_remove(&watch->notifier);
12582a29e30SPaul Durrant         free_watch(watch);
12682a29e30SPaul Durrant 
12782a29e30SPaul Durrant         return NULL;
12882a29e30SPaul Durrant     }
12982a29e30SPaul Durrant 
13082a29e30SPaul Durrant     return watch;
13182a29e30SPaul Durrant }
13282a29e30SPaul Durrant 
13382a29e30SPaul Durrant static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch,
13482a29e30SPaul Durrant                                  Error **errp)
13582a29e30SPaul Durrant {
13682a29e30SPaul Durrant     trace_xen_bus_remove_watch(watch->node, watch->key, watch->token);
13782a29e30SPaul Durrant 
13882a29e30SPaul Durrant     xs_node_unwatch(xenbus->xsh, watch->node, watch->key, watch->token,
13982a29e30SPaul Durrant                     errp);
14082a29e30SPaul Durrant 
14182a29e30SPaul Durrant     notifier_remove(&watch->notifier);
14282a29e30SPaul Durrant     free_watch(watch);
14382a29e30SPaul Durrant }
14482a29e30SPaul Durrant 
145108f7bbaSPaul Durrant static void xen_bus_unrealize(BusState *bus, Error **errp)
146108f7bbaSPaul Durrant {
147094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(bus);
148094a2239SPaul Durrant 
149108f7bbaSPaul Durrant     trace_xen_bus_unrealize();
150094a2239SPaul Durrant 
151094a2239SPaul Durrant     if (!xenbus->xsh) {
152094a2239SPaul Durrant         return;
153094a2239SPaul Durrant     }
154094a2239SPaul Durrant 
15582a29e30SPaul Durrant     qemu_set_fd_handler(xs_fileno(xenbus->xsh), NULL, NULL, NULL);
15682a29e30SPaul Durrant 
157094a2239SPaul Durrant     xs_close(xenbus->xsh);
158108f7bbaSPaul Durrant }
159108f7bbaSPaul Durrant 
16082a29e30SPaul Durrant static void xen_bus_watch(void *opaque)
16182a29e30SPaul Durrant {
16282a29e30SPaul Durrant     XenBus *xenbus = opaque;
16382a29e30SPaul Durrant     char **v;
16482a29e30SPaul Durrant     const char *token;
16582a29e30SPaul Durrant 
16682a29e30SPaul Durrant     g_assert(xenbus->xsh);
16782a29e30SPaul Durrant 
16882a29e30SPaul Durrant     v = xs_check_watch(xenbus->xsh);
16982a29e30SPaul Durrant     if (!v) {
17082a29e30SPaul Durrant         return;
17182a29e30SPaul Durrant     }
17282a29e30SPaul Durrant 
17382a29e30SPaul Durrant     token = v[XS_WATCH_TOKEN];
17482a29e30SPaul Durrant 
17582a29e30SPaul Durrant     trace_xen_bus_watch(token);
17682a29e30SPaul Durrant 
17782a29e30SPaul Durrant     notifier_list_notify(&xenbus->watch_notifiers, (void *)token);
17882a29e30SPaul Durrant 
17982a29e30SPaul Durrant     free(v);
18082a29e30SPaul Durrant }
18182a29e30SPaul Durrant 
182108f7bbaSPaul Durrant static void xen_bus_realize(BusState *bus, Error **errp)
183108f7bbaSPaul Durrant {
184094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(bus);
185094a2239SPaul Durrant     unsigned int domid;
186094a2239SPaul Durrant 
187108f7bbaSPaul Durrant     trace_xen_bus_realize();
188094a2239SPaul Durrant 
189094a2239SPaul Durrant     xenbus->xsh = xs_open(0);
190094a2239SPaul Durrant     if (!xenbus->xsh) {
191094a2239SPaul Durrant         error_setg_errno(errp, errno, "failed xs_open");
192094a2239SPaul Durrant         goto fail;
193094a2239SPaul Durrant     }
194094a2239SPaul Durrant 
195094a2239SPaul Durrant     if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */
196094a2239SPaul Durrant                       "domid", NULL, "%u", &domid) == 1) {
197094a2239SPaul Durrant         xenbus->backend_id = domid;
198094a2239SPaul Durrant     } else {
199094a2239SPaul Durrant         xenbus->backend_id = 0; /* Assume lack of node means dom0 */
200094a2239SPaul Durrant     }
201094a2239SPaul Durrant 
20282a29e30SPaul Durrant     notifier_list_init(&xenbus->watch_notifiers);
20382a29e30SPaul Durrant     qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL,
20482a29e30SPaul Durrant                         xenbus);
205094a2239SPaul Durrant     return;
206094a2239SPaul Durrant 
207094a2239SPaul Durrant fail:
208094a2239SPaul Durrant     xen_bus_unrealize(bus, &error_abort);
209108f7bbaSPaul Durrant }
210108f7bbaSPaul Durrant 
211108f7bbaSPaul Durrant static void xen_bus_class_init(ObjectClass *class, void *data)
212108f7bbaSPaul Durrant {
213108f7bbaSPaul Durrant     BusClass *bus_class = BUS_CLASS(class);
214108f7bbaSPaul Durrant 
215094a2239SPaul Durrant     bus_class->print_dev = xen_bus_print_dev;
216094a2239SPaul Durrant     bus_class->get_dev_path = xen_bus_get_dev_path;
217108f7bbaSPaul Durrant     bus_class->realize = xen_bus_realize;
218108f7bbaSPaul Durrant     bus_class->unrealize = xen_bus_unrealize;
219108f7bbaSPaul Durrant }
220108f7bbaSPaul Durrant 
221108f7bbaSPaul Durrant static const TypeInfo xen_bus_type_info = {
222108f7bbaSPaul Durrant     .name = TYPE_XEN_BUS,
223108f7bbaSPaul Durrant     .parent = TYPE_BUS,
224108f7bbaSPaul Durrant     .instance_size = sizeof(XenBus),
225108f7bbaSPaul Durrant     .class_size = sizeof(XenBusClass),
226108f7bbaSPaul Durrant     .class_init = xen_bus_class_init,
227108f7bbaSPaul Durrant     .interfaces = (InterfaceInfo[]) {
228108f7bbaSPaul Durrant         { TYPE_HOTPLUG_HANDLER },
229108f7bbaSPaul Durrant         { }
230108f7bbaSPaul Durrant     },
231108f7bbaSPaul Durrant };
232108f7bbaSPaul Durrant 
233094a2239SPaul Durrant static void xen_device_backend_printf(XenDevice *xendev, const char *key,
234094a2239SPaul Durrant                                       const char *fmt, ...)
235094a2239SPaul Durrant {
236094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
237094a2239SPaul Durrant     Error *local_err = NULL;
238094a2239SPaul Durrant     va_list ap;
239094a2239SPaul Durrant 
240094a2239SPaul Durrant     g_assert(xenbus->xsh);
241094a2239SPaul Durrant 
242094a2239SPaul Durrant     va_start(ap, fmt);
243094a2239SPaul Durrant     xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
244094a2239SPaul Durrant                     &local_err, fmt, ap);
245094a2239SPaul Durrant     va_end(ap);
246094a2239SPaul Durrant 
247094a2239SPaul Durrant     if (local_err) {
248094a2239SPaul Durrant         error_report_err(local_err);
249094a2239SPaul Durrant     }
250094a2239SPaul Durrant }
251094a2239SPaul Durrant 
25282a29e30SPaul Durrant static int xen_device_backend_scanf(XenDevice *xendev, const char *key,
25382a29e30SPaul Durrant                                     const char *fmt, ...)
25482a29e30SPaul Durrant {
25582a29e30SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
25682a29e30SPaul Durrant     va_list ap;
25782a29e30SPaul Durrant     int rc;
25882a29e30SPaul Durrant 
25982a29e30SPaul Durrant     g_assert(xenbus->xsh);
26082a29e30SPaul Durrant 
26182a29e30SPaul Durrant     va_start(ap, fmt);
26282a29e30SPaul Durrant     rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
26382a29e30SPaul Durrant                         NULL, fmt, ap);
26482a29e30SPaul Durrant     va_end(ap);
26582a29e30SPaul Durrant 
26682a29e30SPaul Durrant     return rc;
26782a29e30SPaul Durrant }
26882a29e30SPaul Durrant 
26982a29e30SPaul Durrant void xen_device_backend_set_state(XenDevice *xendev,
270094a2239SPaul Durrant                                   enum xenbus_state state)
271094a2239SPaul Durrant {
272094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
273094a2239SPaul Durrant 
274094a2239SPaul Durrant     if (xendev->backend_state == state) {
275094a2239SPaul Durrant         return;
276094a2239SPaul Durrant     }
277094a2239SPaul Durrant 
278094a2239SPaul Durrant     trace_xen_device_backend_state(type, xendev->name,
279094a2239SPaul Durrant                                    xs_strstate(state));
280094a2239SPaul Durrant 
281094a2239SPaul Durrant     xendev->backend_state = state;
282094a2239SPaul Durrant     xen_device_backend_printf(xendev, "state", "%u", state);
283094a2239SPaul Durrant }
284094a2239SPaul Durrant 
28582a29e30SPaul Durrant enum xenbus_state xen_device_backend_get_state(XenDevice *xendev)
28682a29e30SPaul Durrant {
28782a29e30SPaul Durrant     return xendev->backend_state;
28882a29e30SPaul Durrant }
28982a29e30SPaul Durrant 
290094a2239SPaul Durrant static void xen_device_backend_create(XenDevice *xendev, Error **errp)
291094a2239SPaul Durrant {
292094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
293094a2239SPaul Durrant     struct xs_permissions perms[2];
294094a2239SPaul Durrant     Error *local_err = NULL;
295094a2239SPaul Durrant 
296094a2239SPaul Durrant     xendev->backend_path = xen_device_get_backend_path(xendev);
297094a2239SPaul Durrant 
298094a2239SPaul Durrant     perms[0].id = xenbus->backend_id;
299094a2239SPaul Durrant     perms[0].perms = XS_PERM_NONE;
300094a2239SPaul Durrant     perms[1].id = xendev->frontend_id;
301094a2239SPaul Durrant     perms[1].perms = XS_PERM_READ;
302094a2239SPaul Durrant 
303094a2239SPaul Durrant     g_assert(xenbus->xsh);
304094a2239SPaul Durrant 
305094a2239SPaul Durrant     xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms,
306094a2239SPaul Durrant                    ARRAY_SIZE(perms), &local_err);
307094a2239SPaul Durrant     if (local_err) {
308094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
309094a2239SPaul Durrant                                 "failed to create backend: ");
310094a2239SPaul Durrant     }
311094a2239SPaul Durrant }
312094a2239SPaul Durrant 
313094a2239SPaul Durrant static void xen_device_backend_destroy(XenDevice *xendev)
314094a2239SPaul Durrant {
315094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
316094a2239SPaul Durrant     Error *local_err = NULL;
317094a2239SPaul Durrant 
318094a2239SPaul Durrant     if (!xendev->backend_path) {
319094a2239SPaul Durrant         return;
320094a2239SPaul Durrant     }
321094a2239SPaul Durrant 
322094a2239SPaul Durrant     g_assert(xenbus->xsh);
323094a2239SPaul Durrant 
324094a2239SPaul Durrant     xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path,
325094a2239SPaul Durrant                     &local_err);
326094a2239SPaul Durrant     g_free(xendev->backend_path);
327094a2239SPaul Durrant     xendev->backend_path = NULL;
328094a2239SPaul Durrant 
329094a2239SPaul Durrant     if (local_err) {
330094a2239SPaul Durrant         error_report_err(local_err);
331094a2239SPaul Durrant     }
332094a2239SPaul Durrant }
333094a2239SPaul Durrant 
334094a2239SPaul Durrant static void xen_device_frontend_printf(XenDevice *xendev, const char *key,
335094a2239SPaul Durrant                                        const char *fmt, ...)
336094a2239SPaul Durrant {
337094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
338094a2239SPaul Durrant     Error *local_err = NULL;
339094a2239SPaul Durrant     va_list ap;
340094a2239SPaul Durrant 
341094a2239SPaul Durrant     g_assert(xenbus->xsh);
342094a2239SPaul Durrant 
343094a2239SPaul Durrant     va_start(ap, fmt);
344094a2239SPaul Durrant     xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
345094a2239SPaul Durrant                     &local_err, fmt, ap);
346094a2239SPaul Durrant     va_end(ap);
347094a2239SPaul Durrant 
348094a2239SPaul Durrant     if (local_err) {
349094a2239SPaul Durrant         error_report_err(local_err);
350094a2239SPaul Durrant     }
351094a2239SPaul Durrant }
352094a2239SPaul Durrant 
35382a29e30SPaul Durrant static int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
35482a29e30SPaul Durrant                                      const char *fmt, ...)
35582a29e30SPaul Durrant {
35682a29e30SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
35782a29e30SPaul Durrant     va_list ap;
35882a29e30SPaul Durrant     int rc;
35982a29e30SPaul Durrant 
36082a29e30SPaul Durrant     g_assert(xenbus->xsh);
36182a29e30SPaul Durrant 
36282a29e30SPaul Durrant     va_start(ap, fmt);
36382a29e30SPaul Durrant     rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
36482a29e30SPaul Durrant                         NULL, fmt, ap);
36582a29e30SPaul Durrant     va_end(ap);
36682a29e30SPaul Durrant 
36782a29e30SPaul Durrant     return rc;
36882a29e30SPaul Durrant }
36982a29e30SPaul Durrant 
370094a2239SPaul Durrant static void xen_device_frontend_set_state(XenDevice *xendev,
371094a2239SPaul Durrant                                           enum xenbus_state state)
372094a2239SPaul Durrant {
373094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
374094a2239SPaul Durrant 
375094a2239SPaul Durrant     if (xendev->frontend_state == state) {
376094a2239SPaul Durrant         return;
377094a2239SPaul Durrant     }
378094a2239SPaul Durrant 
379094a2239SPaul Durrant     trace_xen_device_frontend_state(type, xendev->name,
380094a2239SPaul Durrant                                     xs_strstate(state));
381094a2239SPaul Durrant 
382094a2239SPaul Durrant     xendev->frontend_state = state;
383094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "state", "%u", state);
384094a2239SPaul Durrant }
385094a2239SPaul Durrant 
38682a29e30SPaul Durrant static void xen_device_frontend_changed(void *opaque)
38782a29e30SPaul Durrant {
38882a29e30SPaul Durrant     XenDevice *xendev = opaque;
38982a29e30SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
39082a29e30SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
39182a29e30SPaul Durrant     enum xenbus_state state;
39282a29e30SPaul Durrant 
39382a29e30SPaul Durrant     trace_xen_device_frontend_changed(type, xendev->name);
39482a29e30SPaul Durrant 
39582a29e30SPaul Durrant     if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) {
39682a29e30SPaul Durrant         state = XenbusStateUnknown;
39782a29e30SPaul Durrant     }
39882a29e30SPaul Durrant 
39982a29e30SPaul Durrant     xen_device_frontend_set_state(xendev, state);
40082a29e30SPaul Durrant 
40182a29e30SPaul Durrant     if (xendev_class->frontend_changed) {
40282a29e30SPaul Durrant         Error *local_err = NULL;
40382a29e30SPaul Durrant 
40482a29e30SPaul Durrant         xendev_class->frontend_changed(xendev, state, &local_err);
40582a29e30SPaul Durrant 
40682a29e30SPaul Durrant         if (local_err) {
40782a29e30SPaul Durrant             error_reportf_err(local_err, "frontend change error: ");
40882a29e30SPaul Durrant         }
40982a29e30SPaul Durrant     }
41082a29e30SPaul Durrant 
41182a29e30SPaul Durrant     /*
41282a29e30SPaul Durrant      * If a backend is still 'online' then its state should be cycled
41382a29e30SPaul Durrant      * back round to InitWait in order for a new frontend instance to
41482a29e30SPaul Durrant      * connect. This may happen when, for example, a frontend driver is
41582a29e30SPaul Durrant      * re-installed or updated.
41682a29e30SPaul Durrant      */
41782a29e30SPaul Durrant     if (xendev->backend_state == XenbusStateClosed) {
41882a29e30SPaul Durrant         unsigned int online;
41982a29e30SPaul Durrant 
42082a29e30SPaul Durrant         if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
42182a29e30SPaul Durrant             online = 0;
42282a29e30SPaul Durrant         }
42382a29e30SPaul Durrant 
42482a29e30SPaul Durrant         if (online) {
42582a29e30SPaul Durrant             xen_device_backend_set_state(xendev, XenbusStateInitWait);
42682a29e30SPaul Durrant         }
42782a29e30SPaul Durrant     }
42882a29e30SPaul Durrant }
42982a29e30SPaul Durrant 
430094a2239SPaul Durrant static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
431094a2239SPaul Durrant {
432094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
433094a2239SPaul Durrant     struct xs_permissions perms[2];
434094a2239SPaul Durrant     Error *local_err = NULL;
435094a2239SPaul Durrant 
436094a2239SPaul Durrant     xendev->frontend_path = xen_device_get_frontend_path(xendev);
437094a2239SPaul Durrant 
438094a2239SPaul Durrant     perms[0].id = xendev->frontend_id;
439094a2239SPaul Durrant     perms[0].perms = XS_PERM_NONE;
440094a2239SPaul Durrant     perms[1].id = xenbus->backend_id;
441094a2239SPaul Durrant     perms[1].perms = XS_PERM_READ | XS_PERM_WRITE;
442094a2239SPaul Durrant 
443094a2239SPaul Durrant     g_assert(xenbus->xsh);
444094a2239SPaul Durrant 
445094a2239SPaul Durrant     xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms,
446094a2239SPaul Durrant                    ARRAY_SIZE(perms), &local_err);
447094a2239SPaul Durrant     if (local_err) {
448094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
449094a2239SPaul Durrant                                 "failed to create frontend: ");
45082a29e30SPaul Durrant         return;
45182a29e30SPaul Durrant     }
45282a29e30SPaul Durrant 
45382a29e30SPaul Durrant     xendev->frontend_state_watch =
45482a29e30SPaul Durrant         xen_bus_add_watch(xenbus, xendev->frontend_path, "state",
45582a29e30SPaul Durrant                           xen_device_frontend_changed, xendev, &local_err);
45682a29e30SPaul Durrant     if (local_err) {
45782a29e30SPaul Durrant         error_propagate_prepend(errp, local_err,
45882a29e30SPaul Durrant                                 "failed to watch frontend state: ");
459094a2239SPaul Durrant     }
460094a2239SPaul Durrant }
461094a2239SPaul Durrant 
462094a2239SPaul Durrant static void xen_device_frontend_destroy(XenDevice *xendev)
463094a2239SPaul Durrant {
464094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
465094a2239SPaul Durrant     Error *local_err = NULL;
466094a2239SPaul Durrant 
46782a29e30SPaul Durrant     if (xendev->frontend_state_watch) {
46882a29e30SPaul Durrant         xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL);
46982a29e30SPaul Durrant         xendev->frontend_state_watch = NULL;
47082a29e30SPaul Durrant     }
47182a29e30SPaul Durrant 
472094a2239SPaul Durrant     if (!xendev->frontend_path) {
473094a2239SPaul Durrant         return;
474094a2239SPaul Durrant     }
475094a2239SPaul Durrant 
476094a2239SPaul Durrant     g_assert(xenbus->xsh);
477094a2239SPaul Durrant 
478094a2239SPaul Durrant     xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path,
479094a2239SPaul Durrant                     &local_err);
480094a2239SPaul Durrant     g_free(xendev->frontend_path);
481094a2239SPaul Durrant     xendev->frontend_path = NULL;
482094a2239SPaul Durrant 
483094a2239SPaul Durrant     if (local_err) {
484094a2239SPaul Durrant         error_report_err(local_err);
485094a2239SPaul Durrant     }
486094a2239SPaul Durrant }
487094a2239SPaul Durrant 
488*4b34b5b1SPaul Durrant void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
489*4b34b5b1SPaul Durrant                                    Error **errp)
490*4b34b5b1SPaul Durrant {
491*4b34b5b1SPaul Durrant     if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) {
492*4b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_set_max_grants failed");
493*4b34b5b1SPaul Durrant     }
494*4b34b5b1SPaul Durrant }
495*4b34b5b1SPaul Durrant 
496*4b34b5b1SPaul Durrant void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
497*4b34b5b1SPaul Durrant                                 unsigned int nr_refs, int prot,
498*4b34b5b1SPaul Durrant                                 Error **errp)
499*4b34b5b1SPaul Durrant {
500*4b34b5b1SPaul Durrant     void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs,
501*4b34b5b1SPaul Durrant                                                 xendev->frontend_id, refs,
502*4b34b5b1SPaul Durrant                                                 prot);
503*4b34b5b1SPaul Durrant 
504*4b34b5b1SPaul Durrant     if (!map) {
505*4b34b5b1SPaul Durrant         error_setg_errno(errp, errno,
506*4b34b5b1SPaul Durrant                          "xengnttab_map_domain_grant_refs failed");
507*4b34b5b1SPaul Durrant     }
508*4b34b5b1SPaul Durrant 
509*4b34b5b1SPaul Durrant     return map;
510*4b34b5b1SPaul Durrant }
511*4b34b5b1SPaul Durrant 
512*4b34b5b1SPaul Durrant void xen_device_unmap_grant_refs(XenDevice *xendev, void *map,
513*4b34b5b1SPaul Durrant                                  unsigned int nr_refs, Error **errp)
514*4b34b5b1SPaul Durrant {
515*4b34b5b1SPaul Durrant     if (xengnttab_unmap(xendev->xgth, map, nr_refs)) {
516*4b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_unmap failed");
517*4b34b5b1SPaul Durrant     }
518*4b34b5b1SPaul Durrant }
519*4b34b5b1SPaul Durrant 
520*4b34b5b1SPaul Durrant static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain,
521*4b34b5b1SPaul Durrant                                    XenDeviceGrantCopySegment segs[],
522*4b34b5b1SPaul Durrant                                    unsigned int nr_segs, Error **errp)
523*4b34b5b1SPaul Durrant {
524*4b34b5b1SPaul Durrant     uint32_t *refs = g_new(uint32_t, nr_segs);
525*4b34b5b1SPaul Durrant     int prot = to_domain ? PROT_WRITE : PROT_READ;
526*4b34b5b1SPaul Durrant     void *map;
527*4b34b5b1SPaul Durrant     unsigned int i;
528*4b34b5b1SPaul Durrant 
529*4b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
530*4b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
531*4b34b5b1SPaul Durrant 
532*4b34b5b1SPaul Durrant         refs[i] = to_domain ? seg->dest.foreign.ref :
533*4b34b5b1SPaul Durrant             seg->source.foreign.ref;
534*4b34b5b1SPaul Durrant     }
535*4b34b5b1SPaul Durrant 
536*4b34b5b1SPaul Durrant     map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs,
537*4b34b5b1SPaul Durrant                                           xendev->frontend_id, refs,
538*4b34b5b1SPaul Durrant                                           prot);
539*4b34b5b1SPaul Durrant     if (!map) {
540*4b34b5b1SPaul Durrant         error_setg_errno(errp, errno,
541*4b34b5b1SPaul Durrant                          "xengnttab_map_domain_grant_refs failed");
542*4b34b5b1SPaul Durrant         goto done;
543*4b34b5b1SPaul Durrant     }
544*4b34b5b1SPaul Durrant 
545*4b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
546*4b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
547*4b34b5b1SPaul Durrant         void *page = map + (i * XC_PAGE_SIZE);
548*4b34b5b1SPaul Durrant 
549*4b34b5b1SPaul Durrant         if (to_domain) {
550*4b34b5b1SPaul Durrant             memcpy(page + seg->dest.foreign.offset, seg->source.virt,
551*4b34b5b1SPaul Durrant                    seg->len);
552*4b34b5b1SPaul Durrant         } else {
553*4b34b5b1SPaul Durrant             memcpy(seg->dest.virt, page + seg->source.foreign.offset,
554*4b34b5b1SPaul Durrant                    seg->len);
555*4b34b5b1SPaul Durrant         }
556*4b34b5b1SPaul Durrant     }
557*4b34b5b1SPaul Durrant 
558*4b34b5b1SPaul Durrant     if (xengnttab_unmap(xendev->xgth, map, nr_segs)) {
559*4b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_unmap failed");
560*4b34b5b1SPaul Durrant     }
561*4b34b5b1SPaul Durrant 
562*4b34b5b1SPaul Durrant done:
563*4b34b5b1SPaul Durrant     g_free(refs);
564*4b34b5b1SPaul Durrant }
565*4b34b5b1SPaul Durrant 
566*4b34b5b1SPaul Durrant void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
567*4b34b5b1SPaul Durrant                                 XenDeviceGrantCopySegment segs[],
568*4b34b5b1SPaul Durrant                                 unsigned int nr_segs, Error **errp)
569*4b34b5b1SPaul Durrant {
570*4b34b5b1SPaul Durrant     xengnttab_grant_copy_segment_t *xengnttab_segs;
571*4b34b5b1SPaul Durrant     unsigned int i;
572*4b34b5b1SPaul Durrant 
573*4b34b5b1SPaul Durrant     if (!xendev->feature_grant_copy) {
574*4b34b5b1SPaul Durrant         compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp);
575*4b34b5b1SPaul Durrant         return;
576*4b34b5b1SPaul Durrant     }
577*4b34b5b1SPaul Durrant 
578*4b34b5b1SPaul Durrant     xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs);
579*4b34b5b1SPaul Durrant 
580*4b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
581*4b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
582*4b34b5b1SPaul Durrant         xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
583*4b34b5b1SPaul Durrant 
584*4b34b5b1SPaul Durrant         if (to_domain) {
585*4b34b5b1SPaul Durrant             xengnttab_seg->flags = GNTCOPY_dest_gref;
586*4b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.domid = xendev->frontend_id;
587*4b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref;
588*4b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset;
589*4b34b5b1SPaul Durrant             xengnttab_seg->source.virt = seg->source.virt;
590*4b34b5b1SPaul Durrant         } else {
591*4b34b5b1SPaul Durrant             xengnttab_seg->flags = GNTCOPY_source_gref;
592*4b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.domid = xendev->frontend_id;
593*4b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.ref = seg->source.foreign.ref;
594*4b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.offset =
595*4b34b5b1SPaul Durrant                 seg->source.foreign.offset;
596*4b34b5b1SPaul Durrant             xengnttab_seg->dest.virt = seg->dest.virt;
597*4b34b5b1SPaul Durrant         }
598*4b34b5b1SPaul Durrant 
599*4b34b5b1SPaul Durrant         xengnttab_seg->len = seg->len;
600*4b34b5b1SPaul Durrant     }
601*4b34b5b1SPaul Durrant 
602*4b34b5b1SPaul Durrant     if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) {
603*4b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_grant_copy failed");
604*4b34b5b1SPaul Durrant         goto done;
605*4b34b5b1SPaul Durrant     }
606*4b34b5b1SPaul Durrant 
607*4b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
608*4b34b5b1SPaul Durrant         xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
609*4b34b5b1SPaul Durrant 
610*4b34b5b1SPaul Durrant         if (xengnttab_seg->status != GNTST_okay) {
611*4b34b5b1SPaul Durrant             error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i);
612*4b34b5b1SPaul Durrant             break;
613*4b34b5b1SPaul Durrant         }
614*4b34b5b1SPaul Durrant     }
615*4b34b5b1SPaul Durrant 
616*4b34b5b1SPaul Durrant done:
617*4b34b5b1SPaul Durrant     g_free(xengnttab_segs);
618*4b34b5b1SPaul Durrant }
619*4b34b5b1SPaul Durrant 
620108f7bbaSPaul Durrant static void xen_device_unrealize(DeviceState *dev, Error **errp)
621108f7bbaSPaul Durrant {
622108f7bbaSPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
623108f7bbaSPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
624108f7bbaSPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
625108f7bbaSPaul Durrant 
626094a2239SPaul Durrant     if (!xendev->name) {
627094a2239SPaul Durrant         return;
628094a2239SPaul Durrant     }
629094a2239SPaul Durrant 
630094a2239SPaul Durrant     trace_xen_device_unrealize(type, xendev->name);
631094a2239SPaul Durrant 
632094a2239SPaul Durrant     if (xendev->exit.notify) {
633094a2239SPaul Durrant         qemu_remove_exit_notifier(&xendev->exit);
634094a2239SPaul Durrant         xendev->exit.notify = NULL;
635094a2239SPaul Durrant     }
636108f7bbaSPaul Durrant 
637108f7bbaSPaul Durrant     if (xendev_class->unrealize) {
638108f7bbaSPaul Durrant         xendev_class->unrealize(xendev, errp);
639108f7bbaSPaul Durrant     }
640094a2239SPaul Durrant 
641094a2239SPaul Durrant     xen_device_frontend_destroy(xendev);
642094a2239SPaul Durrant     xen_device_backend_destroy(xendev);
643094a2239SPaul Durrant 
644*4b34b5b1SPaul Durrant     if (xendev->xgth) {
645*4b34b5b1SPaul Durrant         xengnttab_close(xendev->xgth);
646*4b34b5b1SPaul Durrant         xendev->xgth = NULL;
647*4b34b5b1SPaul Durrant     }
648*4b34b5b1SPaul Durrant 
649094a2239SPaul Durrant     g_free(xendev->name);
650094a2239SPaul Durrant     xendev->name = NULL;
651094a2239SPaul Durrant }
652094a2239SPaul Durrant 
653094a2239SPaul Durrant static void xen_device_exit(Notifier *n, void *data)
654094a2239SPaul Durrant {
655094a2239SPaul Durrant     XenDevice *xendev = container_of(n, XenDevice, exit);
656094a2239SPaul Durrant 
657094a2239SPaul Durrant     xen_device_unrealize(DEVICE(xendev), &error_abort);
658108f7bbaSPaul Durrant }
659108f7bbaSPaul Durrant 
660108f7bbaSPaul Durrant static void xen_device_realize(DeviceState *dev, Error **errp)
661108f7bbaSPaul Durrant {
662108f7bbaSPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
663108f7bbaSPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
664094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
665108f7bbaSPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
666108f7bbaSPaul Durrant     Error *local_err = NULL;
667108f7bbaSPaul Durrant 
668094a2239SPaul Durrant     if (xendev->frontend_id == DOMID_INVALID) {
669094a2239SPaul Durrant         xendev->frontend_id = xen_domid;
670094a2239SPaul Durrant     }
671094a2239SPaul Durrant 
672094a2239SPaul Durrant     if (xendev->frontend_id >= DOMID_FIRST_RESERVED) {
673094a2239SPaul Durrant         error_setg(errp, "invalid frontend-id");
674094a2239SPaul Durrant         goto unrealize;
675094a2239SPaul Durrant     }
676094a2239SPaul Durrant 
677094a2239SPaul Durrant     if (!xendev_class->get_name) {
678094a2239SPaul Durrant         error_setg(errp, "get_name method not implemented");
679094a2239SPaul Durrant         goto unrealize;
680094a2239SPaul Durrant     }
681094a2239SPaul Durrant 
682094a2239SPaul Durrant     xendev->name = xendev_class->get_name(xendev, &local_err);
683094a2239SPaul Durrant     if (local_err) {
684094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
685094a2239SPaul Durrant                                 "failed to get device name: ");
686094a2239SPaul Durrant         goto unrealize;
687094a2239SPaul Durrant     }
688094a2239SPaul Durrant 
689094a2239SPaul Durrant     trace_xen_device_realize(type, xendev->name);
690094a2239SPaul Durrant 
691*4b34b5b1SPaul Durrant     xendev->xgth = xengnttab_open(NULL, 0);
692*4b34b5b1SPaul Durrant     if (!xendev->xgth) {
693*4b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "failed xengnttab_open");
694*4b34b5b1SPaul Durrant         goto unrealize;
695*4b34b5b1SPaul Durrant     }
696*4b34b5b1SPaul Durrant 
697*4b34b5b1SPaul Durrant     xendev->feature_grant_copy =
698*4b34b5b1SPaul Durrant         (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0);
699*4b34b5b1SPaul Durrant 
700094a2239SPaul Durrant     xen_device_backend_create(xendev, &local_err);
701094a2239SPaul Durrant     if (local_err) {
702094a2239SPaul Durrant         error_propagate(errp, local_err);
703094a2239SPaul Durrant         goto unrealize;
704094a2239SPaul Durrant     }
705094a2239SPaul Durrant 
706094a2239SPaul Durrant     xen_device_frontend_create(xendev, &local_err);
707094a2239SPaul Durrant     if (local_err) {
708094a2239SPaul Durrant         error_propagate(errp, local_err);
709094a2239SPaul Durrant         goto unrealize;
710094a2239SPaul Durrant     }
711108f7bbaSPaul Durrant 
712108f7bbaSPaul Durrant     if (xendev_class->realize) {
713108f7bbaSPaul Durrant         xendev_class->realize(xendev, &local_err);
714108f7bbaSPaul Durrant         if (local_err) {
715108f7bbaSPaul Durrant             error_propagate(errp, local_err);
716108f7bbaSPaul Durrant             goto unrealize;
717108f7bbaSPaul Durrant         }
718108f7bbaSPaul Durrant     }
719108f7bbaSPaul Durrant 
720094a2239SPaul Durrant     xen_device_backend_printf(xendev, "frontend", "%s",
721094a2239SPaul Durrant                               xendev->frontend_path);
722094a2239SPaul Durrant     xen_device_backend_printf(xendev, "frontend-id", "%u",
723094a2239SPaul Durrant                               xendev->frontend_id);
724094a2239SPaul Durrant     xen_device_backend_printf(xendev, "online", "%u", 1);
725094a2239SPaul Durrant     xen_device_backend_printf(xendev, "hotplug-status", "connected");
726094a2239SPaul Durrant 
727094a2239SPaul Durrant     xen_device_backend_set_state(xendev, XenbusStateInitWait);
728094a2239SPaul Durrant 
729094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "backend", "%s",
730094a2239SPaul Durrant                                xendev->backend_path);
731094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "backend-id", "%u",
732094a2239SPaul Durrant                                xenbus->backend_id);
733094a2239SPaul Durrant 
734094a2239SPaul Durrant     xen_device_frontend_set_state(xendev, XenbusStateInitialising);
735094a2239SPaul Durrant 
736094a2239SPaul Durrant     xendev->exit.notify = xen_device_exit;
737094a2239SPaul Durrant     qemu_add_exit_notifier(&xendev->exit);
738108f7bbaSPaul Durrant     return;
739108f7bbaSPaul Durrant 
740108f7bbaSPaul Durrant unrealize:
741108f7bbaSPaul Durrant     xen_device_unrealize(dev, &error_abort);
742108f7bbaSPaul Durrant }
743108f7bbaSPaul Durrant 
744094a2239SPaul Durrant static Property xen_device_props[] = {
745094a2239SPaul Durrant     DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
746094a2239SPaul Durrant                        DOMID_INVALID),
747094a2239SPaul Durrant     DEFINE_PROP_END_OF_LIST()
748094a2239SPaul Durrant };
749094a2239SPaul Durrant 
750108f7bbaSPaul Durrant static void xen_device_class_init(ObjectClass *class, void *data)
751108f7bbaSPaul Durrant {
752108f7bbaSPaul Durrant     DeviceClass *dev_class = DEVICE_CLASS(class);
753108f7bbaSPaul Durrant 
754108f7bbaSPaul Durrant     dev_class->realize = xen_device_realize;
755108f7bbaSPaul Durrant     dev_class->unrealize = xen_device_unrealize;
756094a2239SPaul Durrant     dev_class->props = xen_device_props;
757108f7bbaSPaul Durrant     dev_class->bus_type = TYPE_XEN_BUS;
758108f7bbaSPaul Durrant }
759108f7bbaSPaul Durrant 
760108f7bbaSPaul Durrant static const TypeInfo xen_device_type_info = {
761108f7bbaSPaul Durrant     .name = TYPE_XEN_DEVICE,
762108f7bbaSPaul Durrant     .parent = TYPE_DEVICE,
763108f7bbaSPaul Durrant     .instance_size = sizeof(XenDevice),
764108f7bbaSPaul Durrant     .abstract = true,
765108f7bbaSPaul Durrant     .class_size = sizeof(XenDeviceClass),
766108f7bbaSPaul Durrant     .class_init = xen_device_class_init,
767108f7bbaSPaul Durrant };
768108f7bbaSPaul Durrant 
769108f7bbaSPaul Durrant typedef struct XenBridge {
770108f7bbaSPaul Durrant     SysBusDevice busdev;
771108f7bbaSPaul Durrant } XenBridge;
772108f7bbaSPaul Durrant 
773108f7bbaSPaul Durrant #define TYPE_XEN_BRIDGE "xen-bridge"
774108f7bbaSPaul Durrant 
775108f7bbaSPaul Durrant static const TypeInfo xen_bridge_type_info = {
776108f7bbaSPaul Durrant     .name = TYPE_XEN_BRIDGE,
777108f7bbaSPaul Durrant     .parent = TYPE_SYS_BUS_DEVICE,
778108f7bbaSPaul Durrant     .instance_size = sizeof(XenBridge),
779108f7bbaSPaul Durrant };
780108f7bbaSPaul Durrant 
781108f7bbaSPaul Durrant static void xen_register_types(void)
782108f7bbaSPaul Durrant {
783108f7bbaSPaul Durrant     type_register_static(&xen_bridge_type_info);
784108f7bbaSPaul Durrant     type_register_static(&xen_bus_type_info);
785108f7bbaSPaul Durrant     type_register_static(&xen_device_type_info);
786108f7bbaSPaul Durrant }
787108f7bbaSPaul Durrant 
788108f7bbaSPaul Durrant type_init(xen_register_types)
789108f7bbaSPaul Durrant 
790108f7bbaSPaul Durrant void xen_bus_init(void)
791108f7bbaSPaul Durrant {
792108f7bbaSPaul Durrant     DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE);
793108f7bbaSPaul Durrant     BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL);
794108f7bbaSPaul Durrant 
795108f7bbaSPaul Durrant     qdev_init_nofail(dev);
796108f7bbaSPaul Durrant     qbus_set_bus_hotplug_handler(bus, &error_abort);
797108f7bbaSPaul Durrant }
798