xref: /openbmc/qemu/hw/xen/xen-bus.c (revision cb3231460747552d70af9d546dc53d8195bcb796)
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"
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 
519*cb323146SAnthony PERARD /*
520*cb323146SAnthony PERARD  * Tell from the state whether the frontend is likely alive,
521*cb323146SAnthony PERARD  * i.e. it will react to a change of state of the backend.
522*cb323146SAnthony PERARD  */
523*cb323146SAnthony PERARD static bool xen_device_state_is_active(enum xenbus_state state)
524*cb323146SAnthony PERARD {
525*cb323146SAnthony PERARD     switch (state) {
526*cb323146SAnthony PERARD     case XenbusStateInitWait:
527*cb323146SAnthony PERARD     case XenbusStateInitialised:
528*cb323146SAnthony PERARD     case XenbusStateConnected:
529*cb323146SAnthony PERARD     case XenbusStateClosing:
530*cb323146SAnthony PERARD         return true;
531*cb323146SAnthony PERARD     default:
532*cb323146SAnthony PERARD         return false;
533*cb323146SAnthony PERARD     }
534*cb323146SAnthony PERARD }
535*cb323146SAnthony PERARD 
536b6af8926SPaul Durrant static void xen_device_backend_changed(void *opaque)
537b6af8926SPaul Durrant {
538b6af8926SPaul Durrant     XenDevice *xendev = opaque;
539b6af8926SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
540b6af8926SPaul Durrant     enum xenbus_state state;
541b6af8926SPaul Durrant     unsigned int online;
542b6af8926SPaul Durrant 
543b6af8926SPaul Durrant     trace_xen_device_backend_changed(type, xendev->name);
544b6af8926SPaul Durrant 
545b6af8926SPaul Durrant     if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) {
546b6af8926SPaul Durrant         state = XenbusStateUnknown;
547b6af8926SPaul Durrant     }
548b6af8926SPaul Durrant 
549b6af8926SPaul Durrant     xen_device_backend_set_state(xendev, state);
550b6af8926SPaul Durrant 
551b6af8926SPaul Durrant     if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
552b6af8926SPaul Durrant         online = 0;
553b6af8926SPaul Durrant     }
554b6af8926SPaul Durrant 
555b6af8926SPaul Durrant     xen_device_backend_set_online(xendev, !!online);
556b6af8926SPaul Durrant 
557b6af8926SPaul Durrant     /*
558b6af8926SPaul Durrant      * If the toolstack (or unplug request callback) has set the backend
559*cb323146SAnthony PERARD      * state to Closing, but there is no active frontend then set the
560*cb323146SAnthony PERARD      * backend state to Closed.
561b6af8926SPaul Durrant      */
562b6af8926SPaul Durrant     if (xendev->backend_state == XenbusStateClosing &&
563*cb323146SAnthony PERARD         !xen_device_state_is_active(state)) {
564b6af8926SPaul Durrant         xen_device_backend_set_state(xendev, XenbusStateClosed);
565b6af8926SPaul Durrant     }
566b6af8926SPaul Durrant 
567b6af8926SPaul Durrant     /*
56867bc8e00SPaul Durrant      * If a backend is still 'online' then we should leave it alone but,
56967bc8e00SPaul Durrant      * if a backend is not 'online', then the device should be destroyed
57067bc8e00SPaul Durrant      * once the state is Closed.
571b6af8926SPaul Durrant      */
57267bc8e00SPaul Durrant     if (!xendev->backend_online &&
573b6af8926SPaul Durrant         (xendev->backend_state == XenbusStateClosed ||
574b6af8926SPaul Durrant          xendev->backend_state == XenbusStateInitialising ||
575b6af8926SPaul Durrant          xendev->backend_state == XenbusStateInitWait ||
576b6af8926SPaul Durrant          xendev->backend_state == XenbusStateUnknown)) {
577a783f8adSPaul Durrant         Error *local_err = NULL;
578a783f8adSPaul Durrant 
579a783f8adSPaul Durrant         if (!xen_backend_try_device_destroy(xendev, &local_err)) {
580b6af8926SPaul Durrant             object_unparent(OBJECT(xendev));
581b6af8926SPaul Durrant         }
582a783f8adSPaul Durrant 
583a783f8adSPaul Durrant         if (local_err) {
584a783f8adSPaul Durrant             error_report_err(local_err);
585a783f8adSPaul Durrant         }
586a783f8adSPaul Durrant     }
587b6af8926SPaul Durrant }
588b6af8926SPaul Durrant 
589094a2239SPaul Durrant static void xen_device_backend_create(XenDevice *xendev, Error **errp)
590094a2239SPaul Durrant {
591094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
592094a2239SPaul Durrant     struct xs_permissions perms[2];
593094a2239SPaul Durrant     Error *local_err = NULL;
594094a2239SPaul Durrant 
595094a2239SPaul Durrant     xendev->backend_path = xen_device_get_backend_path(xendev);
596094a2239SPaul Durrant 
597094a2239SPaul Durrant     perms[0].id = xenbus->backend_id;
598094a2239SPaul Durrant     perms[0].perms = XS_PERM_NONE;
599094a2239SPaul Durrant     perms[1].id = xendev->frontend_id;
600094a2239SPaul Durrant     perms[1].perms = XS_PERM_READ;
601094a2239SPaul Durrant 
602094a2239SPaul Durrant     g_assert(xenbus->xsh);
603094a2239SPaul Durrant 
604094a2239SPaul Durrant     xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms,
605094a2239SPaul Durrant                    ARRAY_SIZE(perms), &local_err);
606094a2239SPaul Durrant     if (local_err) {
607094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
608094a2239SPaul Durrant                                 "failed to create backend: ");
609b6af8926SPaul Durrant         return;
610b6af8926SPaul Durrant     }
611b6af8926SPaul Durrant 
612b6af8926SPaul Durrant     xendev->backend_state_watch =
613b6af8926SPaul Durrant         xen_bus_add_watch(xenbus, xendev->backend_path,
614b6af8926SPaul Durrant                           "state", xen_device_backend_changed,
615b6af8926SPaul Durrant                           xendev, &local_err);
616b6af8926SPaul Durrant     if (local_err) {
617b6af8926SPaul Durrant         error_propagate_prepend(errp, local_err,
618b6af8926SPaul Durrant                                 "failed to watch backend state: ");
619b6af8926SPaul Durrant         return;
620b6af8926SPaul Durrant     }
621b6af8926SPaul Durrant 
622b6af8926SPaul Durrant     xendev->backend_online_watch =
623b6af8926SPaul Durrant         xen_bus_add_watch(xenbus, xendev->backend_path,
624b6af8926SPaul Durrant                           "online", xen_device_backend_changed,
625b6af8926SPaul Durrant                           xendev, &local_err);
626b6af8926SPaul Durrant     if (local_err) {
627b6af8926SPaul Durrant         error_propagate_prepend(errp, local_err,
628b6af8926SPaul Durrant                                 "failed to watch backend online: ");
629b6af8926SPaul Durrant         return;
630094a2239SPaul Durrant     }
631094a2239SPaul Durrant }
632094a2239SPaul Durrant 
633094a2239SPaul Durrant static void xen_device_backend_destroy(XenDevice *xendev)
634094a2239SPaul Durrant {
635094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
636094a2239SPaul Durrant     Error *local_err = NULL;
637094a2239SPaul Durrant 
638b6af8926SPaul Durrant     if (xendev->backend_online_watch) {
639b6af8926SPaul Durrant         xen_bus_remove_watch(xenbus, xendev->backend_online_watch, NULL);
640b6af8926SPaul Durrant         xendev->backend_online_watch = NULL;
641b6af8926SPaul Durrant     }
642b6af8926SPaul Durrant 
643b6af8926SPaul Durrant     if (xendev->backend_state_watch) {
644b6af8926SPaul Durrant         xen_bus_remove_watch(xenbus, xendev->backend_state_watch, NULL);
645b6af8926SPaul Durrant         xendev->backend_state_watch = NULL;
646b6af8926SPaul Durrant     }
647b6af8926SPaul Durrant 
648094a2239SPaul Durrant     if (!xendev->backend_path) {
649094a2239SPaul Durrant         return;
650094a2239SPaul Durrant     }
651094a2239SPaul Durrant 
652094a2239SPaul Durrant     g_assert(xenbus->xsh);
653094a2239SPaul Durrant 
654094a2239SPaul Durrant     xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path,
655094a2239SPaul Durrant                     &local_err);
656094a2239SPaul Durrant     g_free(xendev->backend_path);
657094a2239SPaul Durrant     xendev->backend_path = NULL;
658094a2239SPaul Durrant 
659094a2239SPaul Durrant     if (local_err) {
660094a2239SPaul Durrant         error_report_err(local_err);
661094a2239SPaul Durrant     }
662094a2239SPaul Durrant }
663094a2239SPaul Durrant 
664b6af8926SPaul Durrant void xen_device_frontend_printf(XenDevice *xendev, const char *key,
665094a2239SPaul Durrant                                 const char *fmt, ...)
666094a2239SPaul Durrant {
667094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
668094a2239SPaul Durrant     Error *local_err = NULL;
669094a2239SPaul Durrant     va_list ap;
670094a2239SPaul Durrant 
671094a2239SPaul Durrant     g_assert(xenbus->xsh);
672094a2239SPaul Durrant 
673094a2239SPaul Durrant     va_start(ap, fmt);
674094a2239SPaul Durrant     xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
675094a2239SPaul Durrant                     &local_err, fmt, ap);
676094a2239SPaul Durrant     va_end(ap);
677094a2239SPaul Durrant 
678094a2239SPaul Durrant     if (local_err) {
679094a2239SPaul Durrant         error_report_err(local_err);
680094a2239SPaul Durrant     }
681094a2239SPaul Durrant }
682094a2239SPaul Durrant 
683b6af8926SPaul Durrant int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
68482a29e30SPaul Durrant                               const char *fmt, ...)
68582a29e30SPaul Durrant {
68682a29e30SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
68782a29e30SPaul Durrant     va_list ap;
68882a29e30SPaul Durrant     int rc;
68982a29e30SPaul Durrant 
69082a29e30SPaul Durrant     g_assert(xenbus->xsh);
69182a29e30SPaul Durrant 
69282a29e30SPaul Durrant     va_start(ap, fmt);
69382a29e30SPaul Durrant     rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
69482a29e30SPaul Durrant                         NULL, fmt, ap);
69582a29e30SPaul Durrant     va_end(ap);
69682a29e30SPaul Durrant 
69782a29e30SPaul Durrant     return rc;
69882a29e30SPaul Durrant }
69982a29e30SPaul Durrant 
700094a2239SPaul Durrant static void xen_device_frontend_set_state(XenDevice *xendev,
701094a2239SPaul Durrant                                           enum xenbus_state state)
702094a2239SPaul Durrant {
703094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
704094a2239SPaul Durrant 
705094a2239SPaul Durrant     if (xendev->frontend_state == state) {
706094a2239SPaul Durrant         return;
707094a2239SPaul Durrant     }
708094a2239SPaul Durrant 
709094a2239SPaul Durrant     trace_xen_device_frontend_state(type, xendev->name,
710094a2239SPaul Durrant                                     xs_strstate(state));
711094a2239SPaul Durrant 
712094a2239SPaul Durrant     xendev->frontend_state = state;
713094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "state", "%u", state);
714094a2239SPaul Durrant }
715094a2239SPaul Durrant 
71682a29e30SPaul Durrant static void xen_device_frontend_changed(void *opaque)
71782a29e30SPaul Durrant {
71882a29e30SPaul Durrant     XenDevice *xendev = opaque;
71982a29e30SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
72082a29e30SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
72182a29e30SPaul Durrant     enum xenbus_state state;
72282a29e30SPaul Durrant 
72382a29e30SPaul Durrant     trace_xen_device_frontend_changed(type, xendev->name);
72482a29e30SPaul Durrant 
72582a29e30SPaul Durrant     if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) {
72682a29e30SPaul Durrant         state = XenbusStateUnknown;
72782a29e30SPaul Durrant     }
72882a29e30SPaul Durrant 
72982a29e30SPaul Durrant     xen_device_frontend_set_state(xendev, state);
73082a29e30SPaul Durrant 
73167bc8e00SPaul Durrant     if (state == XenbusStateInitialising &&
73267bc8e00SPaul Durrant         xendev->backend_state == XenbusStateClosed &&
73367bc8e00SPaul Durrant         xendev->backend_online) {
73467bc8e00SPaul Durrant         /*
73567bc8e00SPaul Durrant          * The frontend is re-initializing so switch back to
73667bc8e00SPaul Durrant          * InitWait.
73767bc8e00SPaul Durrant          */
73867bc8e00SPaul Durrant         xen_device_backend_set_state(xendev, XenbusStateInitWait);
73967bc8e00SPaul Durrant         return;
74067bc8e00SPaul Durrant     }
74167bc8e00SPaul Durrant 
74282a29e30SPaul Durrant     if (xendev_class->frontend_changed) {
74382a29e30SPaul Durrant         Error *local_err = NULL;
74482a29e30SPaul Durrant 
74582a29e30SPaul Durrant         xendev_class->frontend_changed(xendev, state, &local_err);
74682a29e30SPaul Durrant 
74782a29e30SPaul Durrant         if (local_err) {
74882a29e30SPaul Durrant             error_reportf_err(local_err, "frontend change error: ");
74982a29e30SPaul Durrant         }
75082a29e30SPaul Durrant     }
75182a29e30SPaul Durrant }
75282a29e30SPaul Durrant 
753094a2239SPaul Durrant static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
754094a2239SPaul Durrant {
755094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
756094a2239SPaul Durrant     struct xs_permissions perms[2];
757094a2239SPaul Durrant     Error *local_err = NULL;
758094a2239SPaul Durrant 
759094a2239SPaul Durrant     xendev->frontend_path = xen_device_get_frontend_path(xendev);
760094a2239SPaul Durrant 
761094a2239SPaul Durrant     perms[0].id = xendev->frontend_id;
762094a2239SPaul Durrant     perms[0].perms = XS_PERM_NONE;
763094a2239SPaul Durrant     perms[1].id = xenbus->backend_id;
764094a2239SPaul Durrant     perms[1].perms = XS_PERM_READ | XS_PERM_WRITE;
765094a2239SPaul Durrant 
766094a2239SPaul Durrant     g_assert(xenbus->xsh);
767094a2239SPaul Durrant 
768094a2239SPaul Durrant     xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms,
769094a2239SPaul Durrant                    ARRAY_SIZE(perms), &local_err);
770094a2239SPaul Durrant     if (local_err) {
771094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
772094a2239SPaul Durrant                                 "failed to create frontend: ");
77382a29e30SPaul Durrant         return;
77482a29e30SPaul Durrant     }
77582a29e30SPaul Durrant 
77682a29e30SPaul Durrant     xendev->frontend_state_watch =
77782a29e30SPaul Durrant         xen_bus_add_watch(xenbus, xendev->frontend_path, "state",
77882a29e30SPaul Durrant                           xen_device_frontend_changed, xendev, &local_err);
77982a29e30SPaul Durrant     if (local_err) {
78082a29e30SPaul Durrant         error_propagate_prepend(errp, local_err,
78182a29e30SPaul Durrant                                 "failed to watch frontend state: ");
782094a2239SPaul Durrant     }
783094a2239SPaul Durrant }
784094a2239SPaul Durrant 
785094a2239SPaul Durrant static void xen_device_frontend_destroy(XenDevice *xendev)
786094a2239SPaul Durrant {
787094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
788094a2239SPaul Durrant     Error *local_err = NULL;
789094a2239SPaul Durrant 
79082a29e30SPaul Durrant     if (xendev->frontend_state_watch) {
79182a29e30SPaul Durrant         xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL);
79282a29e30SPaul Durrant         xendev->frontend_state_watch = NULL;
79382a29e30SPaul Durrant     }
79482a29e30SPaul Durrant 
795094a2239SPaul Durrant     if (!xendev->frontend_path) {
796094a2239SPaul Durrant         return;
797094a2239SPaul Durrant     }
798094a2239SPaul Durrant 
799094a2239SPaul Durrant     g_assert(xenbus->xsh);
800094a2239SPaul Durrant 
801094a2239SPaul Durrant     xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path,
802094a2239SPaul Durrant                     &local_err);
803094a2239SPaul Durrant     g_free(xendev->frontend_path);
804094a2239SPaul Durrant     xendev->frontend_path = NULL;
805094a2239SPaul Durrant 
806094a2239SPaul Durrant     if (local_err) {
807094a2239SPaul Durrant         error_report_err(local_err);
808094a2239SPaul Durrant     }
809094a2239SPaul Durrant }
810094a2239SPaul Durrant 
8114b34b5b1SPaul Durrant void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
8124b34b5b1SPaul Durrant                                    Error **errp)
8134b34b5b1SPaul Durrant {
8144b34b5b1SPaul Durrant     if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) {
8154b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_set_max_grants failed");
8164b34b5b1SPaul Durrant     }
8174b34b5b1SPaul Durrant }
8184b34b5b1SPaul Durrant 
8194b34b5b1SPaul Durrant void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
8204b34b5b1SPaul Durrant                                 unsigned int nr_refs, int prot,
8214b34b5b1SPaul Durrant                                 Error **errp)
8224b34b5b1SPaul Durrant {
8234b34b5b1SPaul Durrant     void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs,
8244b34b5b1SPaul Durrant                                                 xendev->frontend_id, refs,
8254b34b5b1SPaul Durrant                                                 prot);
8264b34b5b1SPaul Durrant 
8274b34b5b1SPaul Durrant     if (!map) {
8284b34b5b1SPaul Durrant         error_setg_errno(errp, errno,
8294b34b5b1SPaul Durrant                          "xengnttab_map_domain_grant_refs failed");
8304b34b5b1SPaul Durrant     }
8314b34b5b1SPaul Durrant 
8324b34b5b1SPaul Durrant     return map;
8334b34b5b1SPaul Durrant }
8344b34b5b1SPaul Durrant 
8354b34b5b1SPaul Durrant void xen_device_unmap_grant_refs(XenDevice *xendev, void *map,
8364b34b5b1SPaul Durrant                                  unsigned int nr_refs, Error **errp)
8374b34b5b1SPaul Durrant {
8384b34b5b1SPaul Durrant     if (xengnttab_unmap(xendev->xgth, map, nr_refs)) {
8394b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_unmap failed");
8404b34b5b1SPaul Durrant     }
8414b34b5b1SPaul Durrant }
8424b34b5b1SPaul Durrant 
8434b34b5b1SPaul Durrant static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain,
8444b34b5b1SPaul Durrant                                    XenDeviceGrantCopySegment segs[],
8454b34b5b1SPaul Durrant                                    unsigned int nr_segs, Error **errp)
8464b34b5b1SPaul Durrant {
8474b34b5b1SPaul Durrant     uint32_t *refs = g_new(uint32_t, nr_segs);
8484b34b5b1SPaul Durrant     int prot = to_domain ? PROT_WRITE : PROT_READ;
8494b34b5b1SPaul Durrant     void *map;
8504b34b5b1SPaul Durrant     unsigned int i;
8514b34b5b1SPaul Durrant 
8524b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
8534b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
8544b34b5b1SPaul Durrant 
8554b34b5b1SPaul Durrant         refs[i] = to_domain ? seg->dest.foreign.ref :
8564b34b5b1SPaul Durrant             seg->source.foreign.ref;
8574b34b5b1SPaul Durrant     }
8584b34b5b1SPaul Durrant 
8594b34b5b1SPaul Durrant     map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs,
8604b34b5b1SPaul Durrant                                           xendev->frontend_id, refs,
8614b34b5b1SPaul Durrant                                           prot);
8624b34b5b1SPaul Durrant     if (!map) {
8634b34b5b1SPaul Durrant         error_setg_errno(errp, errno,
8644b34b5b1SPaul Durrant                          "xengnttab_map_domain_grant_refs failed");
8654b34b5b1SPaul Durrant         goto done;
8664b34b5b1SPaul Durrant     }
8674b34b5b1SPaul Durrant 
8684b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
8694b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
8704b34b5b1SPaul Durrant         void *page = map + (i * XC_PAGE_SIZE);
8714b34b5b1SPaul Durrant 
8724b34b5b1SPaul Durrant         if (to_domain) {
8734b34b5b1SPaul Durrant             memcpy(page + seg->dest.foreign.offset, seg->source.virt,
8744b34b5b1SPaul Durrant                    seg->len);
8754b34b5b1SPaul Durrant         } else {
8764b34b5b1SPaul Durrant             memcpy(seg->dest.virt, page + seg->source.foreign.offset,
8774b34b5b1SPaul Durrant                    seg->len);
8784b34b5b1SPaul Durrant         }
8794b34b5b1SPaul Durrant     }
8804b34b5b1SPaul Durrant 
8814b34b5b1SPaul Durrant     if (xengnttab_unmap(xendev->xgth, map, nr_segs)) {
8824b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_unmap failed");
8834b34b5b1SPaul Durrant     }
8844b34b5b1SPaul Durrant 
8854b34b5b1SPaul Durrant done:
8864b34b5b1SPaul Durrant     g_free(refs);
8874b34b5b1SPaul Durrant }
8884b34b5b1SPaul Durrant 
8894b34b5b1SPaul Durrant void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
8904b34b5b1SPaul Durrant                                 XenDeviceGrantCopySegment segs[],
8914b34b5b1SPaul Durrant                                 unsigned int nr_segs, Error **errp)
8924b34b5b1SPaul Durrant {
8934b34b5b1SPaul Durrant     xengnttab_grant_copy_segment_t *xengnttab_segs;
8944b34b5b1SPaul Durrant     unsigned int i;
8954b34b5b1SPaul Durrant 
8964b34b5b1SPaul Durrant     if (!xendev->feature_grant_copy) {
8974b34b5b1SPaul Durrant         compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp);
8984b34b5b1SPaul Durrant         return;
8994b34b5b1SPaul Durrant     }
9004b34b5b1SPaul Durrant 
9014b34b5b1SPaul Durrant     xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs);
9024b34b5b1SPaul Durrant 
9034b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
9044b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
9054b34b5b1SPaul Durrant         xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
9064b34b5b1SPaul Durrant 
9074b34b5b1SPaul Durrant         if (to_domain) {
9084b34b5b1SPaul Durrant             xengnttab_seg->flags = GNTCOPY_dest_gref;
9094b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.domid = xendev->frontend_id;
9104b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref;
9114b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset;
9124b34b5b1SPaul Durrant             xengnttab_seg->source.virt = seg->source.virt;
9134b34b5b1SPaul Durrant         } else {
9144b34b5b1SPaul Durrant             xengnttab_seg->flags = GNTCOPY_source_gref;
9154b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.domid = xendev->frontend_id;
9164b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.ref = seg->source.foreign.ref;
9174b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.offset =
9184b34b5b1SPaul Durrant                 seg->source.foreign.offset;
9194b34b5b1SPaul Durrant             xengnttab_seg->dest.virt = seg->dest.virt;
9204b34b5b1SPaul Durrant         }
9214b34b5b1SPaul Durrant 
9224b34b5b1SPaul Durrant         xengnttab_seg->len = seg->len;
9234b34b5b1SPaul Durrant     }
9244b34b5b1SPaul Durrant 
9254b34b5b1SPaul Durrant     if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) {
9264b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_grant_copy failed");
9274b34b5b1SPaul Durrant         goto done;
9284b34b5b1SPaul Durrant     }
9294b34b5b1SPaul Durrant 
9304b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
9314b34b5b1SPaul Durrant         xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
9324b34b5b1SPaul Durrant 
9334b34b5b1SPaul Durrant         if (xengnttab_seg->status != GNTST_okay) {
9344b34b5b1SPaul Durrant             error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i);
9354b34b5b1SPaul Durrant             break;
9364b34b5b1SPaul Durrant         }
9374b34b5b1SPaul Durrant     }
9384b34b5b1SPaul Durrant 
9394b34b5b1SPaul Durrant done:
9404b34b5b1SPaul Durrant     g_free(xengnttab_segs);
9414b34b5b1SPaul Durrant }
9424b34b5b1SPaul Durrant 
943a3d669c8SPaul Durrant struct XenEventChannel {
944c0b336eaSPaul Durrant     QLIST_ENTRY(XenEventChannel) list;
94583361a8aSPaul Durrant     AioContext *ctx;
946c0b336eaSPaul Durrant     xenevtchn_handle *xeh;
947a3d669c8SPaul Durrant     evtchn_port_t local_port;
948a3d669c8SPaul Durrant     XenEventHandler handler;
949a3d669c8SPaul Durrant     void *opaque;
950a3d669c8SPaul Durrant };
951a3d669c8SPaul Durrant 
952345f42b4SPaul Durrant static bool xen_device_poll(void *opaque)
953345f42b4SPaul Durrant {
954345f42b4SPaul Durrant     XenEventChannel *channel = opaque;
955345f42b4SPaul Durrant 
956345f42b4SPaul Durrant     return channel->handler(channel->opaque);
957345f42b4SPaul Durrant }
958345f42b4SPaul Durrant 
959c0b336eaSPaul Durrant static void xen_device_event(void *opaque)
960a3d669c8SPaul Durrant {
961c0b336eaSPaul Durrant     XenEventChannel *channel = opaque;
962c0b336eaSPaul Durrant     unsigned long port = xenevtchn_pending(channel->xeh);
963a3d669c8SPaul Durrant 
964a3d669c8SPaul Durrant     if (port == channel->local_port) {
965345f42b4SPaul Durrant         xen_device_poll(channel);
966c0b336eaSPaul Durrant 
967c0b336eaSPaul Durrant         xenevtchn_unmask(channel->xeh, port);
968a3d669c8SPaul Durrant     }
969a3d669c8SPaul Durrant }
970a3d669c8SPaul Durrant 
971a3d669c8SPaul Durrant XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
97283361a8aSPaul Durrant                                                AioContext *ctx,
973a3d669c8SPaul Durrant                                                unsigned int port,
974a3d669c8SPaul Durrant                                                XenEventHandler handler,
975a3d669c8SPaul Durrant                                                void *opaque, Error **errp)
976a3d669c8SPaul Durrant {
977a3d669c8SPaul Durrant     XenEventChannel *channel = g_new0(XenEventChannel, 1);
978a3d669c8SPaul Durrant     xenevtchn_port_or_error_t local_port;
979a3d669c8SPaul Durrant 
980c0b336eaSPaul Durrant     channel->xeh = xenevtchn_open(NULL, 0);
981c0b336eaSPaul Durrant     if (!channel->xeh) {
982c0b336eaSPaul Durrant         error_setg_errno(errp, errno, "failed xenevtchn_open");
983c0b336eaSPaul Durrant         goto fail;
984c0b336eaSPaul Durrant     }
985c0b336eaSPaul Durrant 
986c0b336eaSPaul Durrant     local_port = xenevtchn_bind_interdomain(channel->xeh,
987a3d669c8SPaul Durrant                                             xendev->frontend_id,
988a3d669c8SPaul Durrant                                             port);
989a3d669c8SPaul Durrant     if (local_port < 0) {
990a3d669c8SPaul Durrant         error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed");
991c0b336eaSPaul Durrant         goto fail;
992a3d669c8SPaul Durrant     }
993a3d669c8SPaul Durrant 
994a3d669c8SPaul Durrant     channel->local_port = local_port;
995a3d669c8SPaul Durrant     channel->handler = handler;
996a3d669c8SPaul Durrant     channel->opaque = opaque;
997a3d669c8SPaul Durrant 
99883361a8aSPaul Durrant     channel->ctx = ctx;
99983361a8aSPaul Durrant     aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true,
1000345f42b4SPaul Durrant                        xen_device_event, NULL, xen_device_poll, channel);
1001c0b336eaSPaul Durrant 
1002c0b336eaSPaul Durrant     QLIST_INSERT_HEAD(&xendev->event_channels, channel, list);
1003a3d669c8SPaul Durrant 
1004a3d669c8SPaul Durrant     return channel;
1005c0b336eaSPaul Durrant 
1006c0b336eaSPaul Durrant fail:
1007c0b336eaSPaul Durrant     if (channel->xeh) {
1008c0b336eaSPaul Durrant         xenevtchn_close(channel->xeh);
1009c0b336eaSPaul Durrant     }
1010c0b336eaSPaul Durrant 
1011c0b336eaSPaul Durrant     g_free(channel);
1012c0b336eaSPaul Durrant 
1013c0b336eaSPaul Durrant     return NULL;
1014a3d669c8SPaul Durrant }
1015a3d669c8SPaul Durrant 
1016a3d669c8SPaul Durrant void xen_device_notify_event_channel(XenDevice *xendev,
1017a3d669c8SPaul Durrant                                      XenEventChannel *channel,
1018a3d669c8SPaul Durrant                                      Error **errp)
1019a3d669c8SPaul Durrant {
1020a3d669c8SPaul Durrant     if (!channel) {
1021a3d669c8SPaul Durrant         error_setg(errp, "bad channel");
1022a3d669c8SPaul Durrant         return;
1023a3d669c8SPaul Durrant     }
1024a3d669c8SPaul Durrant 
1025c0b336eaSPaul Durrant     if (xenevtchn_notify(channel->xeh, channel->local_port) < 0) {
1026a3d669c8SPaul Durrant         error_setg_errno(errp, errno, "xenevtchn_notify failed");
1027a3d669c8SPaul Durrant     }
1028a3d669c8SPaul Durrant }
1029a3d669c8SPaul Durrant 
1030a3d669c8SPaul Durrant void xen_device_unbind_event_channel(XenDevice *xendev,
1031a3d669c8SPaul Durrant                                      XenEventChannel *channel,
1032a3d669c8SPaul Durrant                                      Error **errp)
1033a3d669c8SPaul Durrant {
1034a3d669c8SPaul Durrant     if (!channel) {
1035a3d669c8SPaul Durrant         error_setg(errp, "bad channel");
1036a3d669c8SPaul Durrant         return;
1037a3d669c8SPaul Durrant     }
1038a3d669c8SPaul Durrant 
1039c0b336eaSPaul Durrant     QLIST_REMOVE(channel, list);
1040a3d669c8SPaul Durrant 
104183361a8aSPaul Durrant     aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true,
104283361a8aSPaul Durrant                        NULL, NULL, NULL, NULL);
1043c0b336eaSPaul Durrant 
1044c0b336eaSPaul Durrant     if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) {
1045a3d669c8SPaul Durrant         error_setg_errno(errp, errno, "xenevtchn_unbind failed");
1046a3d669c8SPaul Durrant     }
1047a3d669c8SPaul Durrant 
1048c0b336eaSPaul Durrant     xenevtchn_close(channel->xeh);
1049a3d669c8SPaul Durrant     g_free(channel);
1050a3d669c8SPaul Durrant }
1051a3d669c8SPaul Durrant 
1052108f7bbaSPaul Durrant static void xen_device_unrealize(DeviceState *dev, Error **errp)
1053108f7bbaSPaul Durrant {
1054108f7bbaSPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
1055108f7bbaSPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
1056108f7bbaSPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
1057c0b336eaSPaul Durrant     XenEventChannel *channel, *next;
1058108f7bbaSPaul Durrant 
1059094a2239SPaul Durrant     if (!xendev->name) {
1060094a2239SPaul Durrant         return;
1061094a2239SPaul Durrant     }
1062094a2239SPaul Durrant 
1063094a2239SPaul Durrant     trace_xen_device_unrealize(type, xendev->name);
1064094a2239SPaul Durrant 
1065094a2239SPaul Durrant     if (xendev->exit.notify) {
1066094a2239SPaul Durrant         qemu_remove_exit_notifier(&xendev->exit);
1067094a2239SPaul Durrant         xendev->exit.notify = NULL;
1068094a2239SPaul Durrant     }
1069108f7bbaSPaul Durrant 
1070108f7bbaSPaul Durrant     if (xendev_class->unrealize) {
1071108f7bbaSPaul Durrant         xendev_class->unrealize(xendev, errp);
1072108f7bbaSPaul Durrant     }
1073094a2239SPaul Durrant 
1074c0b336eaSPaul Durrant     /* Make sure all event channels are cleaned up */
1075c0b336eaSPaul Durrant     QLIST_FOREACH_SAFE(channel, &xendev->event_channels, list, next) {
1076c0b336eaSPaul Durrant         xen_device_unbind_event_channel(xendev, channel, NULL);
1077c0b336eaSPaul Durrant     }
1078c0b336eaSPaul Durrant 
1079094a2239SPaul Durrant     xen_device_frontend_destroy(xendev);
1080094a2239SPaul Durrant     xen_device_backend_destroy(xendev);
1081094a2239SPaul Durrant 
10824b34b5b1SPaul Durrant     if (xendev->xgth) {
10834b34b5b1SPaul Durrant         xengnttab_close(xendev->xgth);
10844b34b5b1SPaul Durrant         xendev->xgth = NULL;
10854b34b5b1SPaul Durrant     }
10864b34b5b1SPaul Durrant 
1087094a2239SPaul Durrant     g_free(xendev->name);
1088094a2239SPaul Durrant     xendev->name = NULL;
1089094a2239SPaul Durrant }
1090094a2239SPaul Durrant 
1091094a2239SPaul Durrant static void xen_device_exit(Notifier *n, void *data)
1092094a2239SPaul Durrant {
1093094a2239SPaul Durrant     XenDevice *xendev = container_of(n, XenDevice, exit);
1094094a2239SPaul Durrant 
1095094a2239SPaul Durrant     xen_device_unrealize(DEVICE(xendev), &error_abort);
1096108f7bbaSPaul Durrant }
1097108f7bbaSPaul Durrant 
1098108f7bbaSPaul Durrant static void xen_device_realize(DeviceState *dev, Error **errp)
1099108f7bbaSPaul Durrant {
1100108f7bbaSPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
1101108f7bbaSPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
1102094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
1103108f7bbaSPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
1104108f7bbaSPaul Durrant     Error *local_err = NULL;
1105108f7bbaSPaul Durrant 
1106094a2239SPaul Durrant     if (xendev->frontend_id == DOMID_INVALID) {
1107094a2239SPaul Durrant         xendev->frontend_id = xen_domid;
1108094a2239SPaul Durrant     }
1109094a2239SPaul Durrant 
1110094a2239SPaul Durrant     if (xendev->frontend_id >= DOMID_FIRST_RESERVED) {
1111094a2239SPaul Durrant         error_setg(errp, "invalid frontend-id");
1112094a2239SPaul Durrant         goto unrealize;
1113094a2239SPaul Durrant     }
1114094a2239SPaul Durrant 
1115094a2239SPaul Durrant     if (!xendev_class->get_name) {
1116094a2239SPaul Durrant         error_setg(errp, "get_name method not implemented");
1117094a2239SPaul Durrant         goto unrealize;
1118094a2239SPaul Durrant     }
1119094a2239SPaul Durrant 
1120094a2239SPaul Durrant     xendev->name = xendev_class->get_name(xendev, &local_err);
1121094a2239SPaul Durrant     if (local_err) {
1122094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
1123094a2239SPaul Durrant                                 "failed to get device name: ");
1124094a2239SPaul Durrant         goto unrealize;
1125094a2239SPaul Durrant     }
1126094a2239SPaul Durrant 
1127094a2239SPaul Durrant     trace_xen_device_realize(type, xendev->name);
1128094a2239SPaul Durrant 
11294b34b5b1SPaul Durrant     xendev->xgth = xengnttab_open(NULL, 0);
11304b34b5b1SPaul Durrant     if (!xendev->xgth) {
11314b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "failed xengnttab_open");
11324b34b5b1SPaul Durrant         goto unrealize;
11334b34b5b1SPaul Durrant     }
11344b34b5b1SPaul Durrant 
11354b34b5b1SPaul Durrant     xendev->feature_grant_copy =
11364b34b5b1SPaul Durrant         (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0);
11374b34b5b1SPaul Durrant 
1138094a2239SPaul Durrant     xen_device_backend_create(xendev, &local_err);
1139094a2239SPaul Durrant     if (local_err) {
1140094a2239SPaul Durrant         error_propagate(errp, local_err);
1141094a2239SPaul Durrant         goto unrealize;
1142094a2239SPaul Durrant     }
1143094a2239SPaul Durrant 
1144094a2239SPaul Durrant     xen_device_frontend_create(xendev, &local_err);
1145094a2239SPaul Durrant     if (local_err) {
1146094a2239SPaul Durrant         error_propagate(errp, local_err);
1147094a2239SPaul Durrant         goto unrealize;
1148094a2239SPaul Durrant     }
1149108f7bbaSPaul Durrant 
1150108f7bbaSPaul Durrant     if (xendev_class->realize) {
1151108f7bbaSPaul Durrant         xendev_class->realize(xendev, &local_err);
1152108f7bbaSPaul Durrant         if (local_err) {
1153108f7bbaSPaul Durrant             error_propagate(errp, local_err);
1154108f7bbaSPaul Durrant             goto unrealize;
1155108f7bbaSPaul Durrant         }
1156108f7bbaSPaul Durrant     }
1157108f7bbaSPaul Durrant 
1158094a2239SPaul Durrant     xen_device_backend_printf(xendev, "frontend", "%s",
1159094a2239SPaul Durrant                               xendev->frontend_path);
1160094a2239SPaul Durrant     xen_device_backend_printf(xendev, "frontend-id", "%u",
1161094a2239SPaul Durrant                               xendev->frontend_id);
1162094a2239SPaul Durrant     xen_device_backend_printf(xendev, "hotplug-status", "connected");
1163094a2239SPaul Durrant 
1164b6af8926SPaul Durrant     xen_device_backend_set_online(xendev, true);
1165094a2239SPaul Durrant     xen_device_backend_set_state(xendev, XenbusStateInitWait);
1166094a2239SPaul Durrant 
1167094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "backend", "%s",
1168094a2239SPaul Durrant                                xendev->backend_path);
1169094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "backend-id", "%u",
1170094a2239SPaul Durrant                                xenbus->backend_id);
1171094a2239SPaul Durrant 
1172094a2239SPaul Durrant     xen_device_frontend_set_state(xendev, XenbusStateInitialising);
1173094a2239SPaul Durrant 
1174094a2239SPaul Durrant     xendev->exit.notify = xen_device_exit;
1175094a2239SPaul Durrant     qemu_add_exit_notifier(&xendev->exit);
1176108f7bbaSPaul Durrant     return;
1177108f7bbaSPaul Durrant 
1178108f7bbaSPaul Durrant unrealize:
1179108f7bbaSPaul Durrant     xen_device_unrealize(dev, &error_abort);
1180108f7bbaSPaul Durrant }
1181108f7bbaSPaul Durrant 
1182094a2239SPaul Durrant static Property xen_device_props[] = {
1183094a2239SPaul Durrant     DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
1184094a2239SPaul Durrant                        DOMID_INVALID),
1185094a2239SPaul Durrant     DEFINE_PROP_END_OF_LIST()
1186094a2239SPaul Durrant };
1187094a2239SPaul Durrant 
1188108f7bbaSPaul Durrant static void xen_device_class_init(ObjectClass *class, void *data)
1189108f7bbaSPaul Durrant {
1190108f7bbaSPaul Durrant     DeviceClass *dev_class = DEVICE_CLASS(class);
1191108f7bbaSPaul Durrant 
1192108f7bbaSPaul Durrant     dev_class->realize = xen_device_realize;
1193108f7bbaSPaul Durrant     dev_class->unrealize = xen_device_unrealize;
1194094a2239SPaul Durrant     dev_class->props = xen_device_props;
1195108f7bbaSPaul Durrant     dev_class->bus_type = TYPE_XEN_BUS;
1196108f7bbaSPaul Durrant }
1197108f7bbaSPaul Durrant 
1198108f7bbaSPaul Durrant static const TypeInfo xen_device_type_info = {
1199108f7bbaSPaul Durrant     .name = TYPE_XEN_DEVICE,
1200108f7bbaSPaul Durrant     .parent = TYPE_DEVICE,
1201108f7bbaSPaul Durrant     .instance_size = sizeof(XenDevice),
1202108f7bbaSPaul Durrant     .abstract = true,
1203108f7bbaSPaul Durrant     .class_size = sizeof(XenDeviceClass),
1204108f7bbaSPaul Durrant     .class_init = xen_device_class_init,
1205108f7bbaSPaul Durrant };
1206108f7bbaSPaul Durrant 
1207108f7bbaSPaul Durrant typedef struct XenBridge {
1208108f7bbaSPaul Durrant     SysBusDevice busdev;
1209108f7bbaSPaul Durrant } XenBridge;
1210108f7bbaSPaul Durrant 
1211108f7bbaSPaul Durrant #define TYPE_XEN_BRIDGE "xen-bridge"
1212108f7bbaSPaul Durrant 
1213108f7bbaSPaul Durrant static const TypeInfo xen_bridge_type_info = {
1214108f7bbaSPaul Durrant     .name = TYPE_XEN_BRIDGE,
1215108f7bbaSPaul Durrant     .parent = TYPE_SYS_BUS_DEVICE,
1216108f7bbaSPaul Durrant     .instance_size = sizeof(XenBridge),
1217108f7bbaSPaul Durrant };
1218108f7bbaSPaul Durrant 
1219108f7bbaSPaul Durrant static void xen_register_types(void)
1220108f7bbaSPaul Durrant {
1221108f7bbaSPaul Durrant     type_register_static(&xen_bridge_type_info);
1222108f7bbaSPaul Durrant     type_register_static(&xen_bus_type_info);
1223108f7bbaSPaul Durrant     type_register_static(&xen_device_type_info);
1224108f7bbaSPaul Durrant }
1225108f7bbaSPaul Durrant 
1226108f7bbaSPaul Durrant type_init(xen_register_types)
1227108f7bbaSPaul Durrant 
1228108f7bbaSPaul Durrant void xen_bus_init(void)
1229108f7bbaSPaul Durrant {
1230108f7bbaSPaul Durrant     DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE);
1231108f7bbaSPaul Durrant     BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL);
1232108f7bbaSPaul Durrant 
1233108f7bbaSPaul Durrant     qdev_init_nofail(dev);
1234108f7bbaSPaul Durrant     qbus_set_bus_hotplug_handler(bus, &error_abort);
1235108f7bbaSPaul Durrant }
1236