xref: /openbmc/qemu/hw/xen/xen-bus.c (revision c0b336ea19a93801ee2333be525d0473d28a10f8)
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"
12108f7bbaSPaul Durrant #include "hw/hw.h"
13108f7bbaSPaul Durrant #include "hw/sysbus.h"
14094a2239SPaul Durrant #include "hw/xen/xen.h"
15a783f8adSPaul Durrant #include "hw/xen/xen-backend.h"
16108f7bbaSPaul Durrant #include "hw/xen/xen-bus.h"
17094a2239SPaul Durrant #include "hw/xen/xen-bus-helper.h"
18094a2239SPaul Durrant #include "monitor/monitor.h"
19108f7bbaSPaul Durrant #include "qapi/error.h"
20a783f8adSPaul Durrant #include "qapi/qmp/qdict.h"
21094a2239SPaul Durrant #include "sysemu/sysemu.h"
22108f7bbaSPaul Durrant #include "trace.h"
23108f7bbaSPaul Durrant 
24094a2239SPaul Durrant static char *xen_device_get_backend_path(XenDevice *xendev)
25094a2239SPaul Durrant {
26094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
27094a2239SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
28094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
29094a2239SPaul Durrant     const char *backend = xendev_class->backend;
30094a2239SPaul Durrant 
31094a2239SPaul Durrant     if (!backend) {
32094a2239SPaul Durrant         backend = type;
33094a2239SPaul Durrant     }
34094a2239SPaul Durrant 
35094a2239SPaul Durrant     return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s",
36094a2239SPaul Durrant                            xenbus->backend_id, backend, xendev->frontend_id,
37094a2239SPaul Durrant                            xendev->name);
38094a2239SPaul Durrant }
39094a2239SPaul Durrant 
40094a2239SPaul Durrant static char *xen_device_get_frontend_path(XenDevice *xendev)
41094a2239SPaul Durrant {
42094a2239SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
43094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
44094a2239SPaul Durrant     const char *device = xendev_class->device;
45094a2239SPaul Durrant 
46094a2239SPaul Durrant     if (!device) {
47094a2239SPaul Durrant         device = type;
48094a2239SPaul Durrant     }
49094a2239SPaul Durrant 
50094a2239SPaul Durrant     return g_strdup_printf("/local/domain/%u/device/%s/%s",
51094a2239SPaul Durrant                            xendev->frontend_id, device, xendev->name);
52094a2239SPaul Durrant }
53094a2239SPaul Durrant 
54b6af8926SPaul Durrant static void xen_device_unplug(XenDevice *xendev, Error **errp)
55b6af8926SPaul Durrant {
56b6af8926SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
57b6af8926SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
58b6af8926SPaul Durrant     Error *local_err = NULL;
59b6af8926SPaul Durrant     xs_transaction_t tid;
60b6af8926SPaul Durrant 
61b6af8926SPaul Durrant     trace_xen_device_unplug(type, xendev->name);
62b6af8926SPaul Durrant 
63b6af8926SPaul Durrant     /* Mimic the way the Xen toolstack does an unplug */
64b6af8926SPaul Durrant again:
65b6af8926SPaul Durrant     tid = xs_transaction_start(xenbus->xsh);
66b6af8926SPaul Durrant     if (tid == XBT_NULL) {
67b6af8926SPaul Durrant         error_setg_errno(errp, errno, "failed xs_transaction_start");
68b6af8926SPaul Durrant         return;
69b6af8926SPaul Durrant     }
70b6af8926SPaul Durrant 
71b6af8926SPaul Durrant     xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online",
72b6af8926SPaul Durrant                    &local_err, "%u", 0);
73b6af8926SPaul Durrant     if (local_err) {
74b6af8926SPaul Durrant         goto abort;
75b6af8926SPaul Durrant     }
76b6af8926SPaul Durrant 
77b6af8926SPaul Durrant     xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state",
78b6af8926SPaul Durrant                    &local_err, "%u", XenbusStateClosing);
79b6af8926SPaul Durrant     if (local_err) {
80b6af8926SPaul Durrant         goto abort;
81b6af8926SPaul Durrant     }
82b6af8926SPaul Durrant 
83b6af8926SPaul Durrant     if (!xs_transaction_end(xenbus->xsh, tid, false)) {
84b6af8926SPaul Durrant         if (errno == EAGAIN) {
85b6af8926SPaul Durrant             goto again;
86b6af8926SPaul Durrant         }
87b6af8926SPaul Durrant 
88b6af8926SPaul Durrant         error_setg_errno(errp, errno, "failed xs_transaction_end");
89b6af8926SPaul Durrant     }
90b6af8926SPaul Durrant 
91b6af8926SPaul Durrant     return;
92b6af8926SPaul Durrant 
93b6af8926SPaul Durrant abort:
94b6af8926SPaul Durrant     /*
95b6af8926SPaul Durrant      * We only abort if there is already a failure so ignore any error
96b6af8926SPaul Durrant      * from ending the transaction.
97b6af8926SPaul Durrant      */
98b6af8926SPaul Durrant     xs_transaction_end(xenbus->xsh, tid, true);
99b6af8926SPaul Durrant     error_propagate(errp, local_err);
100b6af8926SPaul Durrant }
101b6af8926SPaul Durrant 
102094a2239SPaul Durrant static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent)
103094a2239SPaul Durrant {
104094a2239SPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
105094a2239SPaul Durrant 
106094a2239SPaul Durrant     monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n",
107094a2239SPaul Durrant                    indent, "", xendev->name, xendev->frontend_id);
108094a2239SPaul Durrant }
109094a2239SPaul Durrant 
110094a2239SPaul Durrant static char *xen_bus_get_dev_path(DeviceState *dev)
111094a2239SPaul Durrant {
112094a2239SPaul Durrant     return xen_device_get_backend_path(XEN_DEVICE(dev));
113094a2239SPaul Durrant }
114094a2239SPaul Durrant 
11582a29e30SPaul Durrant struct XenWatch {
11682a29e30SPaul Durrant     char *node, *key;
11782a29e30SPaul Durrant     char *token;
11882a29e30SPaul Durrant     XenWatchHandler handler;
11982a29e30SPaul Durrant     void *opaque;
12082a29e30SPaul Durrant     Notifier notifier;
12182a29e30SPaul Durrant };
12282a29e30SPaul Durrant 
12382a29e30SPaul Durrant static void watch_notify(Notifier *n, void *data)
12482a29e30SPaul Durrant {
12582a29e30SPaul Durrant     XenWatch *watch = container_of(n, XenWatch, notifier);
12682a29e30SPaul Durrant     const char *token = data;
12782a29e30SPaul Durrant 
12882a29e30SPaul Durrant     if (!strcmp(watch->token, token)) {
12982a29e30SPaul Durrant         watch->handler(watch->opaque);
13082a29e30SPaul Durrant     }
13182a29e30SPaul Durrant }
13282a29e30SPaul Durrant 
13382a29e30SPaul Durrant static XenWatch *new_watch(const char *node, const char *key,
13482a29e30SPaul Durrant                            XenWatchHandler handler, void *opaque)
13582a29e30SPaul Durrant {
13682a29e30SPaul Durrant     XenWatch *watch = g_new0(XenWatch, 1);
13782a29e30SPaul Durrant     QemuUUID uuid;
13882a29e30SPaul Durrant 
13982a29e30SPaul Durrant     qemu_uuid_generate(&uuid);
14082a29e30SPaul Durrant 
14182a29e30SPaul Durrant     watch->token = qemu_uuid_unparse_strdup(&uuid);
14282a29e30SPaul Durrant     watch->node = g_strdup(node);
14382a29e30SPaul Durrant     watch->key = g_strdup(key);
14482a29e30SPaul Durrant     watch->handler = handler;
14582a29e30SPaul Durrant     watch->opaque = opaque;
14682a29e30SPaul Durrant     watch->notifier.notify = watch_notify;
14782a29e30SPaul Durrant 
14882a29e30SPaul Durrant     return watch;
14982a29e30SPaul Durrant }
15082a29e30SPaul Durrant 
15182a29e30SPaul Durrant static void free_watch(XenWatch *watch)
15282a29e30SPaul Durrant {
15382a29e30SPaul Durrant     g_free(watch->token);
15482a29e30SPaul Durrant     g_free(watch->key);
15582a29e30SPaul Durrant     g_free(watch->node);
15682a29e30SPaul Durrant 
15782a29e30SPaul Durrant     g_free(watch);
15882a29e30SPaul Durrant }
15982a29e30SPaul Durrant 
16082a29e30SPaul Durrant static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node,
16182a29e30SPaul Durrant                                    const char *key, XenWatchHandler handler,
16282a29e30SPaul Durrant                                    void *opaque, Error **errp)
16382a29e30SPaul Durrant {
16482a29e30SPaul Durrant     XenWatch *watch = new_watch(node, key, handler, opaque);
16582a29e30SPaul Durrant     Error *local_err = NULL;
16682a29e30SPaul Durrant 
16782a29e30SPaul Durrant     trace_xen_bus_add_watch(watch->node, watch->key, watch->token);
16882a29e30SPaul Durrant 
16982a29e30SPaul Durrant     notifier_list_add(&xenbus->watch_notifiers, &watch->notifier);
17082a29e30SPaul Durrant 
17182a29e30SPaul Durrant     xs_node_watch(xenbus->xsh, node, key, watch->token, &local_err);
17282a29e30SPaul Durrant     if (local_err) {
17382a29e30SPaul Durrant         error_propagate(errp, local_err);
17482a29e30SPaul Durrant 
17582a29e30SPaul Durrant         notifier_remove(&watch->notifier);
17682a29e30SPaul Durrant         free_watch(watch);
17782a29e30SPaul Durrant 
17882a29e30SPaul Durrant         return NULL;
17982a29e30SPaul Durrant     }
18082a29e30SPaul Durrant 
18182a29e30SPaul Durrant     return watch;
18282a29e30SPaul Durrant }
18382a29e30SPaul Durrant 
18482a29e30SPaul Durrant static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch,
18582a29e30SPaul Durrant                                  Error **errp)
18682a29e30SPaul Durrant {
18782a29e30SPaul Durrant     trace_xen_bus_remove_watch(watch->node, watch->key, watch->token);
18882a29e30SPaul Durrant 
18982a29e30SPaul Durrant     xs_node_unwatch(xenbus->xsh, watch->node, watch->key, watch->token,
19082a29e30SPaul Durrant                     errp);
19182a29e30SPaul Durrant 
19282a29e30SPaul Durrant     notifier_remove(&watch->notifier);
19382a29e30SPaul Durrant     free_watch(watch);
19482a29e30SPaul Durrant }
19582a29e30SPaul Durrant 
196a783f8adSPaul Durrant static void xen_bus_backend_create(XenBus *xenbus, const char *type,
197a783f8adSPaul Durrant                                    const char *name, char *path,
198a783f8adSPaul Durrant                                    Error **errp)
199a783f8adSPaul Durrant {
200a783f8adSPaul Durrant     xs_transaction_t tid;
201a783f8adSPaul Durrant     char **key;
202a783f8adSPaul Durrant     QDict *opts;
203a783f8adSPaul Durrant     unsigned int i, n;
204a783f8adSPaul Durrant     Error *local_err = NULL;
205a783f8adSPaul Durrant 
206a783f8adSPaul Durrant     trace_xen_bus_backend_create(type, path);
207a783f8adSPaul Durrant 
208a783f8adSPaul Durrant again:
209a783f8adSPaul Durrant     tid = xs_transaction_start(xenbus->xsh);
210a783f8adSPaul Durrant     if (tid == XBT_NULL) {
211a783f8adSPaul Durrant         error_setg(errp, "failed xs_transaction_start");
212a783f8adSPaul Durrant         return;
213a783f8adSPaul Durrant     }
214a783f8adSPaul Durrant 
215a783f8adSPaul Durrant     key = xs_directory(xenbus->xsh, tid, path, &n);
216a783f8adSPaul Durrant     if (!key) {
217a783f8adSPaul Durrant         if (!xs_transaction_end(xenbus->xsh, tid, true)) {
218a783f8adSPaul Durrant             error_setg_errno(errp, errno, "failed xs_transaction_end");
219a783f8adSPaul Durrant         }
220a783f8adSPaul Durrant         return;
221a783f8adSPaul Durrant     }
222a783f8adSPaul Durrant 
223a783f8adSPaul Durrant     opts = qdict_new();
224a783f8adSPaul Durrant     for (i = 0; i < n; i++) {
225a783f8adSPaul Durrant         char *val;
226a783f8adSPaul Durrant 
227a783f8adSPaul Durrant         /*
228a783f8adSPaul Durrant          * Assume anything found in the xenstore backend area, other than
229a783f8adSPaul Durrant          * the keys created for a generic XenDevice, are parameters
230a783f8adSPaul Durrant          * to be used to configure the backend.
231a783f8adSPaul Durrant          */
232a783f8adSPaul Durrant         if (!strcmp(key[i], "state") ||
233a783f8adSPaul Durrant             !strcmp(key[i], "online") ||
234a783f8adSPaul Durrant             !strcmp(key[i], "frontend") ||
235a783f8adSPaul Durrant             !strcmp(key[i], "frontend-id") ||
236a783f8adSPaul Durrant             !strcmp(key[i], "hotplug-status"))
237a783f8adSPaul Durrant             continue;
238a783f8adSPaul Durrant 
239a783f8adSPaul Durrant         if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms",
240a783f8adSPaul Durrant                           &val) == 1) {
241a783f8adSPaul Durrant             qdict_put_str(opts, key[i], val);
242a783f8adSPaul Durrant             free(val);
243a783f8adSPaul Durrant         }
244a783f8adSPaul Durrant     }
245a783f8adSPaul Durrant 
246a783f8adSPaul Durrant     free(key);
247a783f8adSPaul Durrant 
248a783f8adSPaul Durrant     if (!xs_transaction_end(xenbus->xsh, tid, false)) {
249a783f8adSPaul Durrant         qobject_unref(opts);
250a783f8adSPaul Durrant 
251a783f8adSPaul Durrant         if (errno == EAGAIN) {
252a783f8adSPaul Durrant             goto again;
253a783f8adSPaul Durrant         }
254a783f8adSPaul Durrant 
255a783f8adSPaul Durrant         error_setg_errno(errp, errno, "failed xs_transaction_end");
256a783f8adSPaul Durrant         return;
257a783f8adSPaul Durrant     }
258a783f8adSPaul Durrant 
259a783f8adSPaul Durrant     xen_backend_device_create(xenbus, type, name, opts, &local_err);
260a783f8adSPaul Durrant     qobject_unref(opts);
261a783f8adSPaul Durrant 
262a783f8adSPaul Durrant     if (local_err) {
263a783f8adSPaul Durrant         error_propagate_prepend(errp, local_err,
264a783f8adSPaul Durrant                                 "failed to create '%s' device '%s': ",
265a783f8adSPaul Durrant                                 type, name);
266a783f8adSPaul Durrant     }
267a783f8adSPaul Durrant }
268a783f8adSPaul Durrant 
269a783f8adSPaul Durrant static void xen_bus_type_enumerate(XenBus *xenbus, const char *type)
270a783f8adSPaul Durrant {
271a783f8adSPaul Durrant     char *domain_path = g_strdup_printf("backend/%s/%u", type, xen_domid);
272a783f8adSPaul Durrant     char **backend;
273a783f8adSPaul Durrant     unsigned int i, n;
274a783f8adSPaul Durrant 
275a783f8adSPaul Durrant     trace_xen_bus_type_enumerate(type);
276a783f8adSPaul Durrant 
277a783f8adSPaul Durrant     backend = xs_directory(xenbus->xsh, XBT_NULL, domain_path, &n);
278a783f8adSPaul Durrant     if (!backend) {
279a783f8adSPaul Durrant         goto out;
280a783f8adSPaul Durrant     }
281a783f8adSPaul Durrant 
282a783f8adSPaul Durrant     for (i = 0; i < n; i++) {
283a783f8adSPaul Durrant         char *backend_path = g_strdup_printf("%s/%s", domain_path,
284a783f8adSPaul Durrant                                              backend[i]);
285a783f8adSPaul Durrant         enum xenbus_state backend_state;
286a783f8adSPaul Durrant 
287a783f8adSPaul Durrant         if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "state",
288a783f8adSPaul Durrant                           NULL, "%u", &backend_state) != 1)
289a783f8adSPaul Durrant             backend_state = XenbusStateUnknown;
290a783f8adSPaul Durrant 
291a783f8adSPaul Durrant         if (backend_state == XenbusStateInitialising) {
292a783f8adSPaul Durrant             Error *local_err = NULL;
293a783f8adSPaul Durrant 
294a783f8adSPaul Durrant             xen_bus_backend_create(xenbus, type, backend[i], backend_path,
295a783f8adSPaul Durrant                                    &local_err);
296a783f8adSPaul Durrant             if (local_err) {
297a783f8adSPaul Durrant                 error_report_err(local_err);
298a783f8adSPaul Durrant             }
299a783f8adSPaul Durrant         }
300a783f8adSPaul Durrant 
301a783f8adSPaul Durrant         g_free(backend_path);
302a783f8adSPaul Durrant     }
303a783f8adSPaul Durrant 
304a783f8adSPaul Durrant     free(backend);
305a783f8adSPaul Durrant 
306a783f8adSPaul Durrant out:
307a783f8adSPaul Durrant     g_free(domain_path);
308a783f8adSPaul Durrant }
309a783f8adSPaul Durrant 
310a783f8adSPaul Durrant static void xen_bus_enumerate(void *opaque)
311a783f8adSPaul Durrant {
312a783f8adSPaul Durrant     XenBus *xenbus = opaque;
313a783f8adSPaul Durrant     char **type;
314a783f8adSPaul Durrant     unsigned int i, n;
315a783f8adSPaul Durrant 
316a783f8adSPaul Durrant     trace_xen_bus_enumerate();
317a783f8adSPaul Durrant 
318a783f8adSPaul Durrant     type = xs_directory(xenbus->xsh, XBT_NULL, "backend", &n);
319a783f8adSPaul Durrant     if (!type) {
320a783f8adSPaul Durrant         return;
321a783f8adSPaul Durrant     }
322a783f8adSPaul Durrant 
323a783f8adSPaul Durrant     for (i = 0; i < n; i++) {
324a783f8adSPaul Durrant         xen_bus_type_enumerate(xenbus, type[i]);
325a783f8adSPaul Durrant     }
326a783f8adSPaul Durrant 
327a783f8adSPaul Durrant     free(type);
328a783f8adSPaul Durrant }
329a783f8adSPaul Durrant 
330108f7bbaSPaul Durrant static void xen_bus_unrealize(BusState *bus, Error **errp)
331108f7bbaSPaul Durrant {
332094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(bus);
333094a2239SPaul Durrant 
334108f7bbaSPaul Durrant     trace_xen_bus_unrealize();
335094a2239SPaul Durrant 
336a783f8adSPaul Durrant     if (xenbus->backend_watch) {
337a783f8adSPaul Durrant         xen_bus_remove_watch(xenbus, xenbus->backend_watch, NULL);
338a783f8adSPaul Durrant         xenbus->backend_watch = NULL;
339a783f8adSPaul Durrant     }
340a783f8adSPaul Durrant 
341094a2239SPaul Durrant     if (!xenbus->xsh) {
342094a2239SPaul Durrant         return;
343094a2239SPaul Durrant     }
344094a2239SPaul Durrant 
34582a29e30SPaul Durrant     qemu_set_fd_handler(xs_fileno(xenbus->xsh), NULL, NULL, NULL);
34682a29e30SPaul Durrant 
347094a2239SPaul Durrant     xs_close(xenbus->xsh);
348108f7bbaSPaul Durrant }
349108f7bbaSPaul Durrant 
35082a29e30SPaul Durrant static void xen_bus_watch(void *opaque)
35182a29e30SPaul Durrant {
35282a29e30SPaul Durrant     XenBus *xenbus = opaque;
35382a29e30SPaul Durrant     char **v;
35482a29e30SPaul Durrant     const char *token;
35582a29e30SPaul Durrant 
35682a29e30SPaul Durrant     g_assert(xenbus->xsh);
35782a29e30SPaul Durrant 
35882a29e30SPaul Durrant     v = xs_check_watch(xenbus->xsh);
35982a29e30SPaul Durrant     if (!v) {
36082a29e30SPaul Durrant         return;
36182a29e30SPaul Durrant     }
36282a29e30SPaul Durrant 
36382a29e30SPaul Durrant     token = v[XS_WATCH_TOKEN];
36482a29e30SPaul Durrant 
36582a29e30SPaul Durrant     trace_xen_bus_watch(token);
36682a29e30SPaul Durrant 
36782a29e30SPaul Durrant     notifier_list_notify(&xenbus->watch_notifiers, (void *)token);
36882a29e30SPaul Durrant 
36982a29e30SPaul Durrant     free(v);
37082a29e30SPaul Durrant }
37182a29e30SPaul Durrant 
372108f7bbaSPaul Durrant static void xen_bus_realize(BusState *bus, Error **errp)
373108f7bbaSPaul Durrant {
374094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(bus);
375094a2239SPaul Durrant     unsigned int domid;
376a783f8adSPaul Durrant     Error *local_err = NULL;
377094a2239SPaul Durrant 
378108f7bbaSPaul Durrant     trace_xen_bus_realize();
379094a2239SPaul Durrant 
380094a2239SPaul Durrant     xenbus->xsh = xs_open(0);
381094a2239SPaul Durrant     if (!xenbus->xsh) {
382094a2239SPaul Durrant         error_setg_errno(errp, errno, "failed xs_open");
383094a2239SPaul Durrant         goto fail;
384094a2239SPaul Durrant     }
385094a2239SPaul Durrant 
386094a2239SPaul Durrant     if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */
387094a2239SPaul Durrant                       "domid", NULL, "%u", &domid) == 1) {
388094a2239SPaul Durrant         xenbus->backend_id = domid;
389094a2239SPaul Durrant     } else {
390094a2239SPaul Durrant         xenbus->backend_id = 0; /* Assume lack of node means dom0 */
391094a2239SPaul Durrant     }
392094a2239SPaul Durrant 
39382a29e30SPaul Durrant     notifier_list_init(&xenbus->watch_notifiers);
39482a29e30SPaul Durrant     qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL,
39582a29e30SPaul Durrant                         xenbus);
396a783f8adSPaul Durrant 
397a783f8adSPaul Durrant     module_call_init(MODULE_INIT_XEN_BACKEND);
398a783f8adSPaul Durrant 
399a783f8adSPaul Durrant     xenbus->backend_watch =
400a783f8adSPaul Durrant         xen_bus_add_watch(xenbus, "", /* domain root node */
401a783f8adSPaul Durrant                           "backend", xen_bus_enumerate, xenbus, &local_err);
402a783f8adSPaul Durrant     if (local_err) {
403a783f8adSPaul Durrant         /* This need not be treated as a hard error so don't propagate */
404a783f8adSPaul Durrant         error_reportf_err(local_err,
405a783f8adSPaul Durrant                           "failed to set up enumeration watch: ");
406a783f8adSPaul Durrant     }
407a783f8adSPaul Durrant 
408094a2239SPaul Durrant     return;
409094a2239SPaul Durrant 
410094a2239SPaul Durrant fail:
411094a2239SPaul Durrant     xen_bus_unrealize(bus, &error_abort);
412108f7bbaSPaul Durrant }
413108f7bbaSPaul Durrant 
414b6af8926SPaul Durrant static void xen_bus_unplug_request(HotplugHandler *hotplug,
415b6af8926SPaul Durrant                                    DeviceState *dev,
416b6af8926SPaul Durrant                                    Error **errp)
417b6af8926SPaul Durrant {
418b6af8926SPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
419b6af8926SPaul Durrant 
420b6af8926SPaul Durrant     xen_device_unplug(xendev, errp);
421b6af8926SPaul Durrant }
422b6af8926SPaul Durrant 
423108f7bbaSPaul Durrant static void xen_bus_class_init(ObjectClass *class, void *data)
424108f7bbaSPaul Durrant {
425108f7bbaSPaul Durrant     BusClass *bus_class = BUS_CLASS(class);
426b6af8926SPaul Durrant     HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class);
427108f7bbaSPaul Durrant 
428094a2239SPaul Durrant     bus_class->print_dev = xen_bus_print_dev;
429094a2239SPaul Durrant     bus_class->get_dev_path = xen_bus_get_dev_path;
430108f7bbaSPaul Durrant     bus_class->realize = xen_bus_realize;
431108f7bbaSPaul Durrant     bus_class->unrealize = xen_bus_unrealize;
432b6af8926SPaul Durrant 
433b6af8926SPaul Durrant     hotplug_class->unplug_request = xen_bus_unplug_request;
434108f7bbaSPaul Durrant }
435108f7bbaSPaul Durrant 
436108f7bbaSPaul Durrant static const TypeInfo xen_bus_type_info = {
437108f7bbaSPaul Durrant     .name = TYPE_XEN_BUS,
438108f7bbaSPaul Durrant     .parent = TYPE_BUS,
439108f7bbaSPaul Durrant     .instance_size = sizeof(XenBus),
440108f7bbaSPaul Durrant     .class_size = sizeof(XenBusClass),
441108f7bbaSPaul Durrant     .class_init = xen_bus_class_init,
442108f7bbaSPaul Durrant     .interfaces = (InterfaceInfo[]) {
443108f7bbaSPaul Durrant         { TYPE_HOTPLUG_HANDLER },
444108f7bbaSPaul Durrant         { }
445108f7bbaSPaul Durrant     },
446108f7bbaSPaul Durrant };
447108f7bbaSPaul Durrant 
448b6af8926SPaul Durrant void xen_device_backend_printf(XenDevice *xendev, const char *key,
449094a2239SPaul Durrant                                const char *fmt, ...)
450094a2239SPaul Durrant {
451094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
452094a2239SPaul Durrant     Error *local_err = NULL;
453094a2239SPaul Durrant     va_list ap;
454094a2239SPaul Durrant 
455094a2239SPaul Durrant     g_assert(xenbus->xsh);
456094a2239SPaul Durrant 
457094a2239SPaul Durrant     va_start(ap, fmt);
458094a2239SPaul Durrant     xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
459094a2239SPaul Durrant                     &local_err, fmt, ap);
460094a2239SPaul Durrant     va_end(ap);
461094a2239SPaul Durrant 
462094a2239SPaul Durrant     if (local_err) {
463094a2239SPaul Durrant         error_report_err(local_err);
464094a2239SPaul Durrant     }
465094a2239SPaul Durrant }
466094a2239SPaul Durrant 
46782a29e30SPaul Durrant static int xen_device_backend_scanf(XenDevice *xendev, const char *key,
46882a29e30SPaul Durrant                                     const char *fmt, ...)
46982a29e30SPaul Durrant {
47082a29e30SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
47182a29e30SPaul Durrant     va_list ap;
47282a29e30SPaul Durrant     int rc;
47382a29e30SPaul Durrant 
47482a29e30SPaul Durrant     g_assert(xenbus->xsh);
47582a29e30SPaul Durrant 
47682a29e30SPaul Durrant     va_start(ap, fmt);
47782a29e30SPaul Durrant     rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
47882a29e30SPaul Durrant                         NULL, fmt, ap);
47982a29e30SPaul Durrant     va_end(ap);
48082a29e30SPaul Durrant 
48182a29e30SPaul Durrant     return rc;
48282a29e30SPaul Durrant }
48382a29e30SPaul Durrant 
48482a29e30SPaul Durrant void xen_device_backend_set_state(XenDevice *xendev,
485094a2239SPaul Durrant                                   enum xenbus_state state)
486094a2239SPaul Durrant {
487094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
488094a2239SPaul Durrant 
489094a2239SPaul Durrant     if (xendev->backend_state == state) {
490094a2239SPaul Durrant         return;
491094a2239SPaul Durrant     }
492094a2239SPaul Durrant 
493094a2239SPaul Durrant     trace_xen_device_backend_state(type, xendev->name,
494094a2239SPaul Durrant                                    xs_strstate(state));
495094a2239SPaul Durrant 
496094a2239SPaul Durrant     xendev->backend_state = state;
497094a2239SPaul Durrant     xen_device_backend_printf(xendev, "state", "%u", state);
498094a2239SPaul Durrant }
499094a2239SPaul Durrant 
50082a29e30SPaul Durrant enum xenbus_state xen_device_backend_get_state(XenDevice *xendev)
50182a29e30SPaul Durrant {
50282a29e30SPaul Durrant     return xendev->backend_state;
50382a29e30SPaul Durrant }
50482a29e30SPaul Durrant 
505b6af8926SPaul Durrant static void xen_device_backend_set_online(XenDevice *xendev, bool online)
506b6af8926SPaul Durrant {
507b6af8926SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
508b6af8926SPaul Durrant 
509b6af8926SPaul Durrant     if (xendev->backend_online == online) {
510b6af8926SPaul Durrant         return;
511b6af8926SPaul Durrant     }
512b6af8926SPaul Durrant 
513b6af8926SPaul Durrant     trace_xen_device_backend_online(type, xendev->name, online);
514b6af8926SPaul Durrant 
515b6af8926SPaul Durrant     xendev->backend_online = online;
516b6af8926SPaul Durrant     xen_device_backend_printf(xendev, "online", "%u", online);
517b6af8926SPaul Durrant }
518b6af8926SPaul Durrant 
519b6af8926SPaul Durrant static void xen_device_backend_changed(void *opaque)
520b6af8926SPaul Durrant {
521b6af8926SPaul Durrant     XenDevice *xendev = opaque;
522b6af8926SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
523b6af8926SPaul Durrant     enum xenbus_state state;
524b6af8926SPaul Durrant     unsigned int online;
525b6af8926SPaul Durrant 
526b6af8926SPaul Durrant     trace_xen_device_backend_changed(type, xendev->name);
527b6af8926SPaul Durrant 
528b6af8926SPaul Durrant     if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) {
529b6af8926SPaul Durrant         state = XenbusStateUnknown;
530b6af8926SPaul Durrant     }
531b6af8926SPaul Durrant 
532b6af8926SPaul Durrant     xen_device_backend_set_state(xendev, state);
533b6af8926SPaul Durrant 
534b6af8926SPaul Durrant     if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
535b6af8926SPaul Durrant         online = 0;
536b6af8926SPaul Durrant     }
537b6af8926SPaul Durrant 
538b6af8926SPaul Durrant     xen_device_backend_set_online(xendev, !!online);
539b6af8926SPaul Durrant 
540b6af8926SPaul Durrant     /*
541b6af8926SPaul Durrant      * If the toolstack (or unplug request callback) has set the backend
542b6af8926SPaul Durrant      * state to Closing, but there is no active frontend (i.e. the
543b6af8926SPaul Durrant      * state is not Connected) then set the backend state to Closed.
544b6af8926SPaul Durrant      */
545b6af8926SPaul Durrant     if (xendev->backend_state == XenbusStateClosing &&
546b6af8926SPaul Durrant         xendev->frontend_state != XenbusStateConnected) {
547b6af8926SPaul Durrant         xen_device_backend_set_state(xendev, XenbusStateClosed);
548b6af8926SPaul Durrant     }
549b6af8926SPaul Durrant 
550b6af8926SPaul Durrant     /*
55167bc8e00SPaul Durrant      * If a backend is still 'online' then we should leave it alone but,
55267bc8e00SPaul Durrant      * if a backend is not 'online', then the device should be destroyed
55367bc8e00SPaul Durrant      * once the state is Closed.
554b6af8926SPaul Durrant      */
55567bc8e00SPaul Durrant     if (!xendev->backend_online &&
556b6af8926SPaul Durrant         (xendev->backend_state == XenbusStateClosed ||
557b6af8926SPaul Durrant          xendev->backend_state == XenbusStateInitialising ||
558b6af8926SPaul Durrant          xendev->backend_state == XenbusStateInitWait ||
559b6af8926SPaul Durrant          xendev->backend_state == XenbusStateUnknown)) {
560a783f8adSPaul Durrant         Error *local_err = NULL;
561a783f8adSPaul Durrant 
562a783f8adSPaul Durrant         if (!xen_backend_try_device_destroy(xendev, &local_err)) {
563b6af8926SPaul Durrant             object_unparent(OBJECT(xendev));
564b6af8926SPaul Durrant         }
565a783f8adSPaul Durrant 
566a783f8adSPaul Durrant         if (local_err) {
567a783f8adSPaul Durrant             error_report_err(local_err);
568a783f8adSPaul Durrant         }
569a783f8adSPaul Durrant     }
570b6af8926SPaul Durrant }
571b6af8926SPaul Durrant 
572094a2239SPaul Durrant static void xen_device_backend_create(XenDevice *xendev, Error **errp)
573094a2239SPaul Durrant {
574094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
575094a2239SPaul Durrant     struct xs_permissions perms[2];
576094a2239SPaul Durrant     Error *local_err = NULL;
577094a2239SPaul Durrant 
578094a2239SPaul Durrant     xendev->backend_path = xen_device_get_backend_path(xendev);
579094a2239SPaul Durrant 
580094a2239SPaul Durrant     perms[0].id = xenbus->backend_id;
581094a2239SPaul Durrant     perms[0].perms = XS_PERM_NONE;
582094a2239SPaul Durrant     perms[1].id = xendev->frontend_id;
583094a2239SPaul Durrant     perms[1].perms = XS_PERM_READ;
584094a2239SPaul Durrant 
585094a2239SPaul Durrant     g_assert(xenbus->xsh);
586094a2239SPaul Durrant 
587094a2239SPaul Durrant     xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms,
588094a2239SPaul Durrant                    ARRAY_SIZE(perms), &local_err);
589094a2239SPaul Durrant     if (local_err) {
590094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
591094a2239SPaul Durrant                                 "failed to create backend: ");
592b6af8926SPaul Durrant         return;
593b6af8926SPaul Durrant     }
594b6af8926SPaul Durrant 
595b6af8926SPaul Durrant     xendev->backend_state_watch =
596b6af8926SPaul Durrant         xen_bus_add_watch(xenbus, xendev->backend_path,
597b6af8926SPaul Durrant                           "state", xen_device_backend_changed,
598b6af8926SPaul Durrant                           xendev, &local_err);
599b6af8926SPaul Durrant     if (local_err) {
600b6af8926SPaul Durrant         error_propagate_prepend(errp, local_err,
601b6af8926SPaul Durrant                                 "failed to watch backend state: ");
602b6af8926SPaul Durrant         return;
603b6af8926SPaul Durrant     }
604b6af8926SPaul Durrant 
605b6af8926SPaul Durrant     xendev->backend_online_watch =
606b6af8926SPaul Durrant         xen_bus_add_watch(xenbus, xendev->backend_path,
607b6af8926SPaul Durrant                           "online", xen_device_backend_changed,
608b6af8926SPaul Durrant                           xendev, &local_err);
609b6af8926SPaul Durrant     if (local_err) {
610b6af8926SPaul Durrant         error_propagate_prepend(errp, local_err,
611b6af8926SPaul Durrant                                 "failed to watch backend online: ");
612b6af8926SPaul Durrant         return;
613094a2239SPaul Durrant     }
614094a2239SPaul Durrant }
615094a2239SPaul Durrant 
616094a2239SPaul Durrant static void xen_device_backend_destroy(XenDevice *xendev)
617094a2239SPaul Durrant {
618094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
619094a2239SPaul Durrant     Error *local_err = NULL;
620094a2239SPaul Durrant 
621b6af8926SPaul Durrant     if (xendev->backend_online_watch) {
622b6af8926SPaul Durrant         xen_bus_remove_watch(xenbus, xendev->backend_online_watch, NULL);
623b6af8926SPaul Durrant         xendev->backend_online_watch = NULL;
624b6af8926SPaul Durrant     }
625b6af8926SPaul Durrant 
626b6af8926SPaul Durrant     if (xendev->backend_state_watch) {
627b6af8926SPaul Durrant         xen_bus_remove_watch(xenbus, xendev->backend_state_watch, NULL);
628b6af8926SPaul Durrant         xendev->backend_state_watch = NULL;
629b6af8926SPaul Durrant     }
630b6af8926SPaul Durrant 
631094a2239SPaul Durrant     if (!xendev->backend_path) {
632094a2239SPaul Durrant         return;
633094a2239SPaul Durrant     }
634094a2239SPaul Durrant 
635094a2239SPaul Durrant     g_assert(xenbus->xsh);
636094a2239SPaul Durrant 
637094a2239SPaul Durrant     xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path,
638094a2239SPaul Durrant                     &local_err);
639094a2239SPaul Durrant     g_free(xendev->backend_path);
640094a2239SPaul Durrant     xendev->backend_path = NULL;
641094a2239SPaul Durrant 
642094a2239SPaul Durrant     if (local_err) {
643094a2239SPaul Durrant         error_report_err(local_err);
644094a2239SPaul Durrant     }
645094a2239SPaul Durrant }
646094a2239SPaul Durrant 
647b6af8926SPaul Durrant void xen_device_frontend_printf(XenDevice *xendev, const char *key,
648094a2239SPaul Durrant                                 const char *fmt, ...)
649094a2239SPaul Durrant {
650094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
651094a2239SPaul Durrant     Error *local_err = NULL;
652094a2239SPaul Durrant     va_list ap;
653094a2239SPaul Durrant 
654094a2239SPaul Durrant     g_assert(xenbus->xsh);
655094a2239SPaul Durrant 
656094a2239SPaul Durrant     va_start(ap, fmt);
657094a2239SPaul Durrant     xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
658094a2239SPaul Durrant                     &local_err, fmt, ap);
659094a2239SPaul Durrant     va_end(ap);
660094a2239SPaul Durrant 
661094a2239SPaul Durrant     if (local_err) {
662094a2239SPaul Durrant         error_report_err(local_err);
663094a2239SPaul Durrant     }
664094a2239SPaul Durrant }
665094a2239SPaul Durrant 
666b6af8926SPaul Durrant int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
66782a29e30SPaul Durrant                               const char *fmt, ...)
66882a29e30SPaul Durrant {
66982a29e30SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
67082a29e30SPaul Durrant     va_list ap;
67182a29e30SPaul Durrant     int rc;
67282a29e30SPaul Durrant 
67382a29e30SPaul Durrant     g_assert(xenbus->xsh);
67482a29e30SPaul Durrant 
67582a29e30SPaul Durrant     va_start(ap, fmt);
67682a29e30SPaul Durrant     rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
67782a29e30SPaul Durrant                         NULL, fmt, ap);
67882a29e30SPaul Durrant     va_end(ap);
67982a29e30SPaul Durrant 
68082a29e30SPaul Durrant     return rc;
68182a29e30SPaul Durrant }
68282a29e30SPaul Durrant 
683094a2239SPaul Durrant static void xen_device_frontend_set_state(XenDevice *xendev,
684094a2239SPaul Durrant                                           enum xenbus_state state)
685094a2239SPaul Durrant {
686094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
687094a2239SPaul Durrant 
688094a2239SPaul Durrant     if (xendev->frontend_state == state) {
689094a2239SPaul Durrant         return;
690094a2239SPaul Durrant     }
691094a2239SPaul Durrant 
692094a2239SPaul Durrant     trace_xen_device_frontend_state(type, xendev->name,
693094a2239SPaul Durrant                                     xs_strstate(state));
694094a2239SPaul Durrant 
695094a2239SPaul Durrant     xendev->frontend_state = state;
696094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "state", "%u", state);
697094a2239SPaul Durrant }
698094a2239SPaul Durrant 
69982a29e30SPaul Durrant static void xen_device_frontend_changed(void *opaque)
70082a29e30SPaul Durrant {
70182a29e30SPaul Durrant     XenDevice *xendev = opaque;
70282a29e30SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
70382a29e30SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
70482a29e30SPaul Durrant     enum xenbus_state state;
70582a29e30SPaul Durrant 
70682a29e30SPaul Durrant     trace_xen_device_frontend_changed(type, xendev->name);
70782a29e30SPaul Durrant 
70882a29e30SPaul Durrant     if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) {
70982a29e30SPaul Durrant         state = XenbusStateUnknown;
71082a29e30SPaul Durrant     }
71182a29e30SPaul Durrant 
71282a29e30SPaul Durrant     xen_device_frontend_set_state(xendev, state);
71382a29e30SPaul Durrant 
71467bc8e00SPaul Durrant     if (state == XenbusStateInitialising &&
71567bc8e00SPaul Durrant         xendev->backend_state == XenbusStateClosed &&
71667bc8e00SPaul Durrant         xendev->backend_online) {
71767bc8e00SPaul Durrant         /*
71867bc8e00SPaul Durrant          * The frontend is re-initializing so switch back to
71967bc8e00SPaul Durrant          * InitWait.
72067bc8e00SPaul Durrant          */
72167bc8e00SPaul Durrant         xen_device_backend_set_state(xendev, XenbusStateInitWait);
72267bc8e00SPaul Durrant         return;
72367bc8e00SPaul Durrant     }
72467bc8e00SPaul Durrant 
72582a29e30SPaul Durrant     if (xendev_class->frontend_changed) {
72682a29e30SPaul Durrant         Error *local_err = NULL;
72782a29e30SPaul Durrant 
72882a29e30SPaul Durrant         xendev_class->frontend_changed(xendev, state, &local_err);
72982a29e30SPaul Durrant 
73082a29e30SPaul Durrant         if (local_err) {
73182a29e30SPaul Durrant             error_reportf_err(local_err, "frontend change error: ");
73282a29e30SPaul Durrant         }
73382a29e30SPaul Durrant     }
73482a29e30SPaul Durrant }
73582a29e30SPaul Durrant 
736094a2239SPaul Durrant static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
737094a2239SPaul Durrant {
738094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
739094a2239SPaul Durrant     struct xs_permissions perms[2];
740094a2239SPaul Durrant     Error *local_err = NULL;
741094a2239SPaul Durrant 
742094a2239SPaul Durrant     xendev->frontend_path = xen_device_get_frontend_path(xendev);
743094a2239SPaul Durrant 
744094a2239SPaul Durrant     perms[0].id = xendev->frontend_id;
745094a2239SPaul Durrant     perms[0].perms = XS_PERM_NONE;
746094a2239SPaul Durrant     perms[1].id = xenbus->backend_id;
747094a2239SPaul Durrant     perms[1].perms = XS_PERM_READ | XS_PERM_WRITE;
748094a2239SPaul Durrant 
749094a2239SPaul Durrant     g_assert(xenbus->xsh);
750094a2239SPaul Durrant 
751094a2239SPaul Durrant     xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms,
752094a2239SPaul Durrant                    ARRAY_SIZE(perms), &local_err);
753094a2239SPaul Durrant     if (local_err) {
754094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
755094a2239SPaul Durrant                                 "failed to create frontend: ");
75682a29e30SPaul Durrant         return;
75782a29e30SPaul Durrant     }
75882a29e30SPaul Durrant 
75982a29e30SPaul Durrant     xendev->frontend_state_watch =
76082a29e30SPaul Durrant         xen_bus_add_watch(xenbus, xendev->frontend_path, "state",
76182a29e30SPaul Durrant                           xen_device_frontend_changed, xendev, &local_err);
76282a29e30SPaul Durrant     if (local_err) {
76382a29e30SPaul Durrant         error_propagate_prepend(errp, local_err,
76482a29e30SPaul Durrant                                 "failed to watch frontend state: ");
765094a2239SPaul Durrant     }
766094a2239SPaul Durrant }
767094a2239SPaul Durrant 
768094a2239SPaul Durrant static void xen_device_frontend_destroy(XenDevice *xendev)
769094a2239SPaul Durrant {
770094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
771094a2239SPaul Durrant     Error *local_err = NULL;
772094a2239SPaul Durrant 
77382a29e30SPaul Durrant     if (xendev->frontend_state_watch) {
77482a29e30SPaul Durrant         xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL);
77582a29e30SPaul Durrant         xendev->frontend_state_watch = NULL;
77682a29e30SPaul Durrant     }
77782a29e30SPaul Durrant 
778094a2239SPaul Durrant     if (!xendev->frontend_path) {
779094a2239SPaul Durrant         return;
780094a2239SPaul Durrant     }
781094a2239SPaul Durrant 
782094a2239SPaul Durrant     g_assert(xenbus->xsh);
783094a2239SPaul Durrant 
784094a2239SPaul Durrant     xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path,
785094a2239SPaul Durrant                     &local_err);
786094a2239SPaul Durrant     g_free(xendev->frontend_path);
787094a2239SPaul Durrant     xendev->frontend_path = NULL;
788094a2239SPaul Durrant 
789094a2239SPaul Durrant     if (local_err) {
790094a2239SPaul Durrant         error_report_err(local_err);
791094a2239SPaul Durrant     }
792094a2239SPaul Durrant }
793094a2239SPaul Durrant 
7944b34b5b1SPaul Durrant void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
7954b34b5b1SPaul Durrant                                    Error **errp)
7964b34b5b1SPaul Durrant {
7974b34b5b1SPaul Durrant     if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) {
7984b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_set_max_grants failed");
7994b34b5b1SPaul Durrant     }
8004b34b5b1SPaul Durrant }
8014b34b5b1SPaul Durrant 
8024b34b5b1SPaul Durrant void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
8034b34b5b1SPaul Durrant                                 unsigned int nr_refs, int prot,
8044b34b5b1SPaul Durrant                                 Error **errp)
8054b34b5b1SPaul Durrant {
8064b34b5b1SPaul Durrant     void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs,
8074b34b5b1SPaul Durrant                                                 xendev->frontend_id, refs,
8084b34b5b1SPaul Durrant                                                 prot);
8094b34b5b1SPaul Durrant 
8104b34b5b1SPaul Durrant     if (!map) {
8114b34b5b1SPaul Durrant         error_setg_errno(errp, errno,
8124b34b5b1SPaul Durrant                          "xengnttab_map_domain_grant_refs failed");
8134b34b5b1SPaul Durrant     }
8144b34b5b1SPaul Durrant 
8154b34b5b1SPaul Durrant     return map;
8164b34b5b1SPaul Durrant }
8174b34b5b1SPaul Durrant 
8184b34b5b1SPaul Durrant void xen_device_unmap_grant_refs(XenDevice *xendev, void *map,
8194b34b5b1SPaul Durrant                                  unsigned int nr_refs, Error **errp)
8204b34b5b1SPaul Durrant {
8214b34b5b1SPaul Durrant     if (xengnttab_unmap(xendev->xgth, map, nr_refs)) {
8224b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_unmap failed");
8234b34b5b1SPaul Durrant     }
8244b34b5b1SPaul Durrant }
8254b34b5b1SPaul Durrant 
8264b34b5b1SPaul Durrant static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain,
8274b34b5b1SPaul Durrant                                    XenDeviceGrantCopySegment segs[],
8284b34b5b1SPaul Durrant                                    unsigned int nr_segs, Error **errp)
8294b34b5b1SPaul Durrant {
8304b34b5b1SPaul Durrant     uint32_t *refs = g_new(uint32_t, nr_segs);
8314b34b5b1SPaul Durrant     int prot = to_domain ? PROT_WRITE : PROT_READ;
8324b34b5b1SPaul Durrant     void *map;
8334b34b5b1SPaul Durrant     unsigned int i;
8344b34b5b1SPaul Durrant 
8354b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
8364b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
8374b34b5b1SPaul Durrant 
8384b34b5b1SPaul Durrant         refs[i] = to_domain ? seg->dest.foreign.ref :
8394b34b5b1SPaul Durrant             seg->source.foreign.ref;
8404b34b5b1SPaul Durrant     }
8414b34b5b1SPaul Durrant 
8424b34b5b1SPaul Durrant     map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs,
8434b34b5b1SPaul Durrant                                           xendev->frontend_id, refs,
8444b34b5b1SPaul Durrant                                           prot);
8454b34b5b1SPaul Durrant     if (!map) {
8464b34b5b1SPaul Durrant         error_setg_errno(errp, errno,
8474b34b5b1SPaul Durrant                          "xengnttab_map_domain_grant_refs failed");
8484b34b5b1SPaul Durrant         goto done;
8494b34b5b1SPaul Durrant     }
8504b34b5b1SPaul Durrant 
8514b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
8524b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
8534b34b5b1SPaul Durrant         void *page = map + (i * XC_PAGE_SIZE);
8544b34b5b1SPaul Durrant 
8554b34b5b1SPaul Durrant         if (to_domain) {
8564b34b5b1SPaul Durrant             memcpy(page + seg->dest.foreign.offset, seg->source.virt,
8574b34b5b1SPaul Durrant                    seg->len);
8584b34b5b1SPaul Durrant         } else {
8594b34b5b1SPaul Durrant             memcpy(seg->dest.virt, page + seg->source.foreign.offset,
8604b34b5b1SPaul Durrant                    seg->len);
8614b34b5b1SPaul Durrant         }
8624b34b5b1SPaul Durrant     }
8634b34b5b1SPaul Durrant 
8644b34b5b1SPaul Durrant     if (xengnttab_unmap(xendev->xgth, map, nr_segs)) {
8654b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_unmap failed");
8664b34b5b1SPaul Durrant     }
8674b34b5b1SPaul Durrant 
8684b34b5b1SPaul Durrant done:
8694b34b5b1SPaul Durrant     g_free(refs);
8704b34b5b1SPaul Durrant }
8714b34b5b1SPaul Durrant 
8724b34b5b1SPaul Durrant void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
8734b34b5b1SPaul Durrant                                 XenDeviceGrantCopySegment segs[],
8744b34b5b1SPaul Durrant                                 unsigned int nr_segs, Error **errp)
8754b34b5b1SPaul Durrant {
8764b34b5b1SPaul Durrant     xengnttab_grant_copy_segment_t *xengnttab_segs;
8774b34b5b1SPaul Durrant     unsigned int i;
8784b34b5b1SPaul Durrant 
8794b34b5b1SPaul Durrant     if (!xendev->feature_grant_copy) {
8804b34b5b1SPaul Durrant         compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp);
8814b34b5b1SPaul Durrant         return;
8824b34b5b1SPaul Durrant     }
8834b34b5b1SPaul Durrant 
8844b34b5b1SPaul Durrant     xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs);
8854b34b5b1SPaul Durrant 
8864b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
8874b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
8884b34b5b1SPaul Durrant         xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
8894b34b5b1SPaul Durrant 
8904b34b5b1SPaul Durrant         if (to_domain) {
8914b34b5b1SPaul Durrant             xengnttab_seg->flags = GNTCOPY_dest_gref;
8924b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.domid = xendev->frontend_id;
8934b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref;
8944b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset;
8954b34b5b1SPaul Durrant             xengnttab_seg->source.virt = seg->source.virt;
8964b34b5b1SPaul Durrant         } else {
8974b34b5b1SPaul Durrant             xengnttab_seg->flags = GNTCOPY_source_gref;
8984b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.domid = xendev->frontend_id;
8994b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.ref = seg->source.foreign.ref;
9004b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.offset =
9014b34b5b1SPaul Durrant                 seg->source.foreign.offset;
9024b34b5b1SPaul Durrant             xengnttab_seg->dest.virt = seg->dest.virt;
9034b34b5b1SPaul Durrant         }
9044b34b5b1SPaul Durrant 
9054b34b5b1SPaul Durrant         xengnttab_seg->len = seg->len;
9064b34b5b1SPaul Durrant     }
9074b34b5b1SPaul Durrant 
9084b34b5b1SPaul Durrant     if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) {
9094b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_grant_copy failed");
9104b34b5b1SPaul Durrant         goto done;
9114b34b5b1SPaul Durrant     }
9124b34b5b1SPaul Durrant 
9134b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
9144b34b5b1SPaul Durrant         xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
9154b34b5b1SPaul Durrant 
9164b34b5b1SPaul Durrant         if (xengnttab_seg->status != GNTST_okay) {
9174b34b5b1SPaul Durrant             error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i);
9184b34b5b1SPaul Durrant             break;
9194b34b5b1SPaul Durrant         }
9204b34b5b1SPaul Durrant     }
9214b34b5b1SPaul Durrant 
9224b34b5b1SPaul Durrant done:
9234b34b5b1SPaul Durrant     g_free(xengnttab_segs);
9244b34b5b1SPaul Durrant }
9254b34b5b1SPaul Durrant 
926a3d669c8SPaul Durrant struct XenEventChannel {
927*c0b336eaSPaul Durrant     QLIST_ENTRY(XenEventChannel) list;
928*c0b336eaSPaul Durrant     xenevtchn_handle *xeh;
929a3d669c8SPaul Durrant     evtchn_port_t local_port;
930a3d669c8SPaul Durrant     XenEventHandler handler;
931a3d669c8SPaul Durrant     void *opaque;
932a3d669c8SPaul Durrant };
933a3d669c8SPaul Durrant 
934*c0b336eaSPaul Durrant static void xen_device_event(void *opaque)
935a3d669c8SPaul Durrant {
936*c0b336eaSPaul Durrant     XenEventChannel *channel = opaque;
937*c0b336eaSPaul Durrant     unsigned long port = xenevtchn_pending(channel->xeh);
938a3d669c8SPaul Durrant 
939a3d669c8SPaul Durrant     if (port == channel->local_port) {
940a3d669c8SPaul Durrant         channel->handler(channel->opaque);
941*c0b336eaSPaul Durrant 
942*c0b336eaSPaul Durrant         xenevtchn_unmask(channel->xeh, port);
943a3d669c8SPaul Durrant     }
944a3d669c8SPaul Durrant }
945a3d669c8SPaul Durrant 
946a3d669c8SPaul Durrant XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
947a3d669c8SPaul Durrant                                                unsigned int port,
948a3d669c8SPaul Durrant                                                XenEventHandler handler,
949a3d669c8SPaul Durrant                                                void *opaque, Error **errp)
950a3d669c8SPaul Durrant {
951a3d669c8SPaul Durrant     XenEventChannel *channel = g_new0(XenEventChannel, 1);
952a3d669c8SPaul Durrant     xenevtchn_port_or_error_t local_port;
953a3d669c8SPaul Durrant 
954*c0b336eaSPaul Durrant     channel->xeh = xenevtchn_open(NULL, 0);
955*c0b336eaSPaul Durrant     if (!channel->xeh) {
956*c0b336eaSPaul Durrant         error_setg_errno(errp, errno, "failed xenevtchn_open");
957*c0b336eaSPaul Durrant         goto fail;
958*c0b336eaSPaul Durrant     }
959*c0b336eaSPaul Durrant 
960*c0b336eaSPaul Durrant     local_port = xenevtchn_bind_interdomain(channel->xeh,
961a3d669c8SPaul Durrant                                             xendev->frontend_id,
962a3d669c8SPaul Durrant                                             port);
963a3d669c8SPaul Durrant     if (local_port < 0) {
964a3d669c8SPaul Durrant         error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed");
965*c0b336eaSPaul Durrant         goto fail;
966a3d669c8SPaul Durrant     }
967a3d669c8SPaul Durrant 
968a3d669c8SPaul Durrant     channel->local_port = local_port;
969a3d669c8SPaul Durrant     channel->handler = handler;
970a3d669c8SPaul Durrant     channel->opaque = opaque;
971a3d669c8SPaul Durrant 
972*c0b336eaSPaul Durrant     qemu_set_fd_handler(xenevtchn_fd(channel->xeh), xen_device_event, NULL,
973*c0b336eaSPaul Durrant                         channel);
974*c0b336eaSPaul Durrant 
975*c0b336eaSPaul Durrant     QLIST_INSERT_HEAD(&xendev->event_channels, channel, list);
976a3d669c8SPaul Durrant 
977a3d669c8SPaul Durrant     return channel;
978*c0b336eaSPaul Durrant 
979*c0b336eaSPaul Durrant fail:
980*c0b336eaSPaul Durrant     if (channel->xeh) {
981*c0b336eaSPaul Durrant         xenevtchn_close(channel->xeh);
982*c0b336eaSPaul Durrant     }
983*c0b336eaSPaul Durrant 
984*c0b336eaSPaul Durrant     g_free(channel);
985*c0b336eaSPaul Durrant 
986*c0b336eaSPaul Durrant     return NULL;
987a3d669c8SPaul Durrant }
988a3d669c8SPaul Durrant 
989a3d669c8SPaul Durrant void xen_device_notify_event_channel(XenDevice *xendev,
990a3d669c8SPaul Durrant                                      XenEventChannel *channel,
991a3d669c8SPaul Durrant                                      Error **errp)
992a3d669c8SPaul Durrant {
993a3d669c8SPaul Durrant     if (!channel) {
994a3d669c8SPaul Durrant         error_setg(errp, "bad channel");
995a3d669c8SPaul Durrant         return;
996a3d669c8SPaul Durrant     }
997a3d669c8SPaul Durrant 
998*c0b336eaSPaul Durrant     if (xenevtchn_notify(channel->xeh, channel->local_port) < 0) {
999a3d669c8SPaul Durrant         error_setg_errno(errp, errno, "xenevtchn_notify failed");
1000a3d669c8SPaul Durrant     }
1001a3d669c8SPaul Durrant }
1002a3d669c8SPaul Durrant 
1003a3d669c8SPaul Durrant void xen_device_unbind_event_channel(XenDevice *xendev,
1004a3d669c8SPaul Durrant                                      XenEventChannel *channel,
1005a3d669c8SPaul Durrant                                      Error **errp)
1006a3d669c8SPaul Durrant {
1007a3d669c8SPaul Durrant     if (!channel) {
1008a3d669c8SPaul Durrant         error_setg(errp, "bad channel");
1009a3d669c8SPaul Durrant         return;
1010a3d669c8SPaul Durrant     }
1011a3d669c8SPaul Durrant 
1012*c0b336eaSPaul Durrant     QLIST_REMOVE(channel, list);
1013a3d669c8SPaul Durrant 
1014*c0b336eaSPaul Durrant     qemu_set_fd_handler(xenevtchn_fd(channel->xeh), NULL, NULL, NULL);
1015*c0b336eaSPaul Durrant 
1016*c0b336eaSPaul Durrant     if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) {
1017a3d669c8SPaul Durrant         error_setg_errno(errp, errno, "xenevtchn_unbind failed");
1018a3d669c8SPaul Durrant     }
1019a3d669c8SPaul Durrant 
1020*c0b336eaSPaul Durrant     xenevtchn_close(channel->xeh);
1021a3d669c8SPaul Durrant     g_free(channel);
1022a3d669c8SPaul Durrant }
1023a3d669c8SPaul Durrant 
1024108f7bbaSPaul Durrant static void xen_device_unrealize(DeviceState *dev, Error **errp)
1025108f7bbaSPaul Durrant {
1026108f7bbaSPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
1027108f7bbaSPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
1028108f7bbaSPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
1029*c0b336eaSPaul Durrant     XenEventChannel *channel, *next;
1030108f7bbaSPaul Durrant 
1031094a2239SPaul Durrant     if (!xendev->name) {
1032094a2239SPaul Durrant         return;
1033094a2239SPaul Durrant     }
1034094a2239SPaul Durrant 
1035094a2239SPaul Durrant     trace_xen_device_unrealize(type, xendev->name);
1036094a2239SPaul Durrant 
1037094a2239SPaul Durrant     if (xendev->exit.notify) {
1038094a2239SPaul Durrant         qemu_remove_exit_notifier(&xendev->exit);
1039094a2239SPaul Durrant         xendev->exit.notify = NULL;
1040094a2239SPaul Durrant     }
1041108f7bbaSPaul Durrant 
1042108f7bbaSPaul Durrant     if (xendev_class->unrealize) {
1043108f7bbaSPaul Durrant         xendev_class->unrealize(xendev, errp);
1044108f7bbaSPaul Durrant     }
1045094a2239SPaul Durrant 
1046*c0b336eaSPaul Durrant     /* Make sure all event channels are cleaned up */
1047*c0b336eaSPaul Durrant     QLIST_FOREACH_SAFE(channel, &xendev->event_channels, list, next) {
1048*c0b336eaSPaul Durrant         xen_device_unbind_event_channel(xendev, channel, NULL);
1049*c0b336eaSPaul Durrant     }
1050*c0b336eaSPaul Durrant 
1051094a2239SPaul Durrant     xen_device_frontend_destroy(xendev);
1052094a2239SPaul Durrant     xen_device_backend_destroy(xendev);
1053094a2239SPaul Durrant 
10544b34b5b1SPaul Durrant     if (xendev->xgth) {
10554b34b5b1SPaul Durrant         xengnttab_close(xendev->xgth);
10564b34b5b1SPaul Durrant         xendev->xgth = NULL;
10574b34b5b1SPaul Durrant     }
10584b34b5b1SPaul Durrant 
1059094a2239SPaul Durrant     g_free(xendev->name);
1060094a2239SPaul Durrant     xendev->name = NULL;
1061094a2239SPaul Durrant }
1062094a2239SPaul Durrant 
1063094a2239SPaul Durrant static void xen_device_exit(Notifier *n, void *data)
1064094a2239SPaul Durrant {
1065094a2239SPaul Durrant     XenDevice *xendev = container_of(n, XenDevice, exit);
1066094a2239SPaul Durrant 
1067094a2239SPaul Durrant     xen_device_unrealize(DEVICE(xendev), &error_abort);
1068108f7bbaSPaul Durrant }
1069108f7bbaSPaul Durrant 
1070108f7bbaSPaul Durrant static void xen_device_realize(DeviceState *dev, Error **errp)
1071108f7bbaSPaul Durrant {
1072108f7bbaSPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
1073108f7bbaSPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
1074094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
1075108f7bbaSPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
1076108f7bbaSPaul Durrant     Error *local_err = NULL;
1077108f7bbaSPaul Durrant 
1078094a2239SPaul Durrant     if (xendev->frontend_id == DOMID_INVALID) {
1079094a2239SPaul Durrant         xendev->frontend_id = xen_domid;
1080094a2239SPaul Durrant     }
1081094a2239SPaul Durrant 
1082094a2239SPaul Durrant     if (xendev->frontend_id >= DOMID_FIRST_RESERVED) {
1083094a2239SPaul Durrant         error_setg(errp, "invalid frontend-id");
1084094a2239SPaul Durrant         goto unrealize;
1085094a2239SPaul Durrant     }
1086094a2239SPaul Durrant 
1087094a2239SPaul Durrant     if (!xendev_class->get_name) {
1088094a2239SPaul Durrant         error_setg(errp, "get_name method not implemented");
1089094a2239SPaul Durrant         goto unrealize;
1090094a2239SPaul Durrant     }
1091094a2239SPaul Durrant 
1092094a2239SPaul Durrant     xendev->name = xendev_class->get_name(xendev, &local_err);
1093094a2239SPaul Durrant     if (local_err) {
1094094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
1095094a2239SPaul Durrant                                 "failed to get device name: ");
1096094a2239SPaul Durrant         goto unrealize;
1097094a2239SPaul Durrant     }
1098094a2239SPaul Durrant 
1099094a2239SPaul Durrant     trace_xen_device_realize(type, xendev->name);
1100094a2239SPaul Durrant 
11014b34b5b1SPaul Durrant     xendev->xgth = xengnttab_open(NULL, 0);
11024b34b5b1SPaul Durrant     if (!xendev->xgth) {
11034b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "failed xengnttab_open");
11044b34b5b1SPaul Durrant         goto unrealize;
11054b34b5b1SPaul Durrant     }
11064b34b5b1SPaul Durrant 
11074b34b5b1SPaul Durrant     xendev->feature_grant_copy =
11084b34b5b1SPaul Durrant         (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0);
11094b34b5b1SPaul Durrant 
1110094a2239SPaul Durrant     xen_device_backend_create(xendev, &local_err);
1111094a2239SPaul Durrant     if (local_err) {
1112094a2239SPaul Durrant         error_propagate(errp, local_err);
1113094a2239SPaul Durrant         goto unrealize;
1114094a2239SPaul Durrant     }
1115094a2239SPaul Durrant 
1116094a2239SPaul Durrant     xen_device_frontend_create(xendev, &local_err);
1117094a2239SPaul Durrant     if (local_err) {
1118094a2239SPaul Durrant         error_propagate(errp, local_err);
1119094a2239SPaul Durrant         goto unrealize;
1120094a2239SPaul Durrant     }
1121108f7bbaSPaul Durrant 
1122108f7bbaSPaul Durrant     if (xendev_class->realize) {
1123108f7bbaSPaul Durrant         xendev_class->realize(xendev, &local_err);
1124108f7bbaSPaul Durrant         if (local_err) {
1125108f7bbaSPaul Durrant             error_propagate(errp, local_err);
1126108f7bbaSPaul Durrant             goto unrealize;
1127108f7bbaSPaul Durrant         }
1128108f7bbaSPaul Durrant     }
1129108f7bbaSPaul Durrant 
1130094a2239SPaul Durrant     xen_device_backend_printf(xendev, "frontend", "%s",
1131094a2239SPaul Durrant                               xendev->frontend_path);
1132094a2239SPaul Durrant     xen_device_backend_printf(xendev, "frontend-id", "%u",
1133094a2239SPaul Durrant                               xendev->frontend_id);
1134094a2239SPaul Durrant     xen_device_backend_printf(xendev, "hotplug-status", "connected");
1135094a2239SPaul Durrant 
1136b6af8926SPaul Durrant     xen_device_backend_set_online(xendev, true);
1137094a2239SPaul Durrant     xen_device_backend_set_state(xendev, XenbusStateInitWait);
1138094a2239SPaul Durrant 
1139094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "backend", "%s",
1140094a2239SPaul Durrant                                xendev->backend_path);
1141094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "backend-id", "%u",
1142094a2239SPaul Durrant                                xenbus->backend_id);
1143094a2239SPaul Durrant 
1144094a2239SPaul Durrant     xen_device_frontend_set_state(xendev, XenbusStateInitialising);
1145094a2239SPaul Durrant 
1146094a2239SPaul Durrant     xendev->exit.notify = xen_device_exit;
1147094a2239SPaul Durrant     qemu_add_exit_notifier(&xendev->exit);
1148108f7bbaSPaul Durrant     return;
1149108f7bbaSPaul Durrant 
1150108f7bbaSPaul Durrant unrealize:
1151108f7bbaSPaul Durrant     xen_device_unrealize(dev, &error_abort);
1152108f7bbaSPaul Durrant }
1153108f7bbaSPaul Durrant 
1154094a2239SPaul Durrant static Property xen_device_props[] = {
1155094a2239SPaul Durrant     DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
1156094a2239SPaul Durrant                        DOMID_INVALID),
1157094a2239SPaul Durrant     DEFINE_PROP_END_OF_LIST()
1158094a2239SPaul Durrant };
1159094a2239SPaul Durrant 
1160108f7bbaSPaul Durrant static void xen_device_class_init(ObjectClass *class, void *data)
1161108f7bbaSPaul Durrant {
1162108f7bbaSPaul Durrant     DeviceClass *dev_class = DEVICE_CLASS(class);
1163108f7bbaSPaul Durrant 
1164108f7bbaSPaul Durrant     dev_class->realize = xen_device_realize;
1165108f7bbaSPaul Durrant     dev_class->unrealize = xen_device_unrealize;
1166094a2239SPaul Durrant     dev_class->props = xen_device_props;
1167108f7bbaSPaul Durrant     dev_class->bus_type = TYPE_XEN_BUS;
1168108f7bbaSPaul Durrant }
1169108f7bbaSPaul Durrant 
1170108f7bbaSPaul Durrant static const TypeInfo xen_device_type_info = {
1171108f7bbaSPaul Durrant     .name = TYPE_XEN_DEVICE,
1172108f7bbaSPaul Durrant     .parent = TYPE_DEVICE,
1173108f7bbaSPaul Durrant     .instance_size = sizeof(XenDevice),
1174108f7bbaSPaul Durrant     .abstract = true,
1175108f7bbaSPaul Durrant     .class_size = sizeof(XenDeviceClass),
1176108f7bbaSPaul Durrant     .class_init = xen_device_class_init,
1177108f7bbaSPaul Durrant };
1178108f7bbaSPaul Durrant 
1179108f7bbaSPaul Durrant typedef struct XenBridge {
1180108f7bbaSPaul Durrant     SysBusDevice busdev;
1181108f7bbaSPaul Durrant } XenBridge;
1182108f7bbaSPaul Durrant 
1183108f7bbaSPaul Durrant #define TYPE_XEN_BRIDGE "xen-bridge"
1184108f7bbaSPaul Durrant 
1185108f7bbaSPaul Durrant static const TypeInfo xen_bridge_type_info = {
1186108f7bbaSPaul Durrant     .name = TYPE_XEN_BRIDGE,
1187108f7bbaSPaul Durrant     .parent = TYPE_SYS_BUS_DEVICE,
1188108f7bbaSPaul Durrant     .instance_size = sizeof(XenBridge),
1189108f7bbaSPaul Durrant };
1190108f7bbaSPaul Durrant 
1191108f7bbaSPaul Durrant static void xen_register_types(void)
1192108f7bbaSPaul Durrant {
1193108f7bbaSPaul Durrant     type_register_static(&xen_bridge_type_info);
1194108f7bbaSPaul Durrant     type_register_static(&xen_bus_type_info);
1195108f7bbaSPaul Durrant     type_register_static(&xen_device_type_info);
1196108f7bbaSPaul Durrant }
1197108f7bbaSPaul Durrant 
1198108f7bbaSPaul Durrant type_init(xen_register_types)
1199108f7bbaSPaul Durrant 
1200108f7bbaSPaul Durrant void xen_bus_init(void)
1201108f7bbaSPaul Durrant {
1202108f7bbaSPaul Durrant     DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE);
1203108f7bbaSPaul Durrant     BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL);
1204108f7bbaSPaul Durrant 
1205108f7bbaSPaul Durrant     qdev_init_nofail(dev);
1206108f7bbaSPaul Durrant     qbus_set_bus_hotplug_handler(bus, &error_abort);
1207108f7bbaSPaul Durrant }
1208