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