xref: /openbmc/qemu/hw/xen/xen-bus.c (revision a3d669c8bd1a93ad588d4dce5c70ea6405fa9bb9)
1108f7bbaSPaul Durrant /*
2108f7bbaSPaul Durrant  * Copyright (c) 2018  Citrix Systems Inc.
3108f7bbaSPaul Durrant  *
4108f7bbaSPaul Durrant  * This work is licensed under the terms of the GNU GPL, version 2 or later.
5108f7bbaSPaul Durrant  * See the COPYING file in the top-level directory.
6108f7bbaSPaul Durrant  */
7108f7bbaSPaul Durrant 
8108f7bbaSPaul Durrant #include "qemu/osdep.h"
982a29e30SPaul Durrant #include "qemu/main-loop.h"
1082a29e30SPaul Durrant #include "qemu/uuid.h"
11108f7bbaSPaul Durrant #include "hw/hw.h"
12108f7bbaSPaul Durrant #include "hw/sysbus.h"
13094a2239SPaul Durrant #include "hw/xen/xen.h"
14108f7bbaSPaul Durrant #include "hw/xen/xen-bus.h"
15094a2239SPaul Durrant #include "hw/xen/xen-bus-helper.h"
16094a2239SPaul Durrant #include "monitor/monitor.h"
17108f7bbaSPaul Durrant #include "qapi/error.h"
18094a2239SPaul Durrant #include "sysemu/sysemu.h"
19108f7bbaSPaul Durrant #include "trace.h"
20108f7bbaSPaul Durrant 
21094a2239SPaul Durrant static char *xen_device_get_backend_path(XenDevice *xendev)
22094a2239SPaul Durrant {
23094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
24094a2239SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
25094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
26094a2239SPaul Durrant     const char *backend = xendev_class->backend;
27094a2239SPaul Durrant 
28094a2239SPaul Durrant     if (!backend) {
29094a2239SPaul Durrant         backend = type;
30094a2239SPaul Durrant     }
31094a2239SPaul Durrant 
32094a2239SPaul Durrant     return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s",
33094a2239SPaul Durrant                            xenbus->backend_id, backend, xendev->frontend_id,
34094a2239SPaul Durrant                            xendev->name);
35094a2239SPaul Durrant }
36094a2239SPaul Durrant 
37094a2239SPaul Durrant static char *xen_device_get_frontend_path(XenDevice *xendev)
38094a2239SPaul Durrant {
39094a2239SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
40094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
41094a2239SPaul Durrant     const char *device = xendev_class->device;
42094a2239SPaul Durrant 
43094a2239SPaul Durrant     if (!device) {
44094a2239SPaul Durrant         device = type;
45094a2239SPaul Durrant     }
46094a2239SPaul Durrant 
47094a2239SPaul Durrant     return g_strdup_printf("/local/domain/%u/device/%s/%s",
48094a2239SPaul Durrant                            xendev->frontend_id, device, xendev->name);
49094a2239SPaul Durrant }
50094a2239SPaul Durrant 
51094a2239SPaul Durrant static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent)
52094a2239SPaul Durrant {
53094a2239SPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
54094a2239SPaul Durrant 
55094a2239SPaul Durrant     monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n",
56094a2239SPaul Durrant                    indent, "", xendev->name, xendev->frontend_id);
57094a2239SPaul Durrant }
58094a2239SPaul Durrant 
59094a2239SPaul Durrant static char *xen_bus_get_dev_path(DeviceState *dev)
60094a2239SPaul Durrant {
61094a2239SPaul Durrant     return xen_device_get_backend_path(XEN_DEVICE(dev));
62094a2239SPaul Durrant }
63094a2239SPaul Durrant 
6482a29e30SPaul Durrant struct XenWatch {
6582a29e30SPaul Durrant     char *node, *key;
6682a29e30SPaul Durrant     char *token;
6782a29e30SPaul Durrant     XenWatchHandler handler;
6882a29e30SPaul Durrant     void *opaque;
6982a29e30SPaul Durrant     Notifier notifier;
7082a29e30SPaul Durrant };
7182a29e30SPaul Durrant 
7282a29e30SPaul Durrant static void watch_notify(Notifier *n, void *data)
7382a29e30SPaul Durrant {
7482a29e30SPaul Durrant     XenWatch *watch = container_of(n, XenWatch, notifier);
7582a29e30SPaul Durrant     const char *token = data;
7682a29e30SPaul Durrant 
7782a29e30SPaul Durrant     if (!strcmp(watch->token, token)) {
7882a29e30SPaul Durrant         watch->handler(watch->opaque);
7982a29e30SPaul Durrant     }
8082a29e30SPaul Durrant }
8182a29e30SPaul Durrant 
8282a29e30SPaul Durrant static XenWatch *new_watch(const char *node, const char *key,
8382a29e30SPaul Durrant                            XenWatchHandler handler, void *opaque)
8482a29e30SPaul Durrant {
8582a29e30SPaul Durrant     XenWatch *watch = g_new0(XenWatch, 1);
8682a29e30SPaul Durrant     QemuUUID uuid;
8782a29e30SPaul Durrant 
8882a29e30SPaul Durrant     qemu_uuid_generate(&uuid);
8982a29e30SPaul Durrant 
9082a29e30SPaul Durrant     watch->token = qemu_uuid_unparse_strdup(&uuid);
9182a29e30SPaul Durrant     watch->node = g_strdup(node);
9282a29e30SPaul Durrant     watch->key = g_strdup(key);
9382a29e30SPaul Durrant     watch->handler = handler;
9482a29e30SPaul Durrant     watch->opaque = opaque;
9582a29e30SPaul Durrant     watch->notifier.notify = watch_notify;
9682a29e30SPaul Durrant 
9782a29e30SPaul Durrant     return watch;
9882a29e30SPaul Durrant }
9982a29e30SPaul Durrant 
10082a29e30SPaul Durrant static void free_watch(XenWatch *watch)
10182a29e30SPaul Durrant {
10282a29e30SPaul Durrant     g_free(watch->token);
10382a29e30SPaul Durrant     g_free(watch->key);
10482a29e30SPaul Durrant     g_free(watch->node);
10582a29e30SPaul Durrant 
10682a29e30SPaul Durrant     g_free(watch);
10782a29e30SPaul Durrant }
10882a29e30SPaul Durrant 
10982a29e30SPaul Durrant static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node,
11082a29e30SPaul Durrant                                    const char *key, XenWatchHandler handler,
11182a29e30SPaul Durrant                                    void *opaque, Error **errp)
11282a29e30SPaul Durrant {
11382a29e30SPaul Durrant     XenWatch *watch = new_watch(node, key, handler, opaque);
11482a29e30SPaul Durrant     Error *local_err = NULL;
11582a29e30SPaul Durrant 
11682a29e30SPaul Durrant     trace_xen_bus_add_watch(watch->node, watch->key, watch->token);
11782a29e30SPaul Durrant 
11882a29e30SPaul Durrant     notifier_list_add(&xenbus->watch_notifiers, &watch->notifier);
11982a29e30SPaul Durrant 
12082a29e30SPaul Durrant     xs_node_watch(xenbus->xsh, node, key, watch->token, &local_err);
12182a29e30SPaul Durrant     if (local_err) {
12282a29e30SPaul Durrant         error_propagate(errp, local_err);
12382a29e30SPaul Durrant 
12482a29e30SPaul Durrant         notifier_remove(&watch->notifier);
12582a29e30SPaul Durrant         free_watch(watch);
12682a29e30SPaul Durrant 
12782a29e30SPaul Durrant         return NULL;
12882a29e30SPaul Durrant     }
12982a29e30SPaul Durrant 
13082a29e30SPaul Durrant     return watch;
13182a29e30SPaul Durrant }
13282a29e30SPaul Durrant 
13382a29e30SPaul Durrant static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch,
13482a29e30SPaul Durrant                                  Error **errp)
13582a29e30SPaul Durrant {
13682a29e30SPaul Durrant     trace_xen_bus_remove_watch(watch->node, watch->key, watch->token);
13782a29e30SPaul Durrant 
13882a29e30SPaul Durrant     xs_node_unwatch(xenbus->xsh, watch->node, watch->key, watch->token,
13982a29e30SPaul Durrant                     errp);
14082a29e30SPaul Durrant 
14182a29e30SPaul Durrant     notifier_remove(&watch->notifier);
14282a29e30SPaul Durrant     free_watch(watch);
14382a29e30SPaul Durrant }
14482a29e30SPaul Durrant 
145108f7bbaSPaul Durrant static void xen_bus_unrealize(BusState *bus, Error **errp)
146108f7bbaSPaul Durrant {
147094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(bus);
148094a2239SPaul Durrant 
149108f7bbaSPaul Durrant     trace_xen_bus_unrealize();
150094a2239SPaul Durrant 
151094a2239SPaul Durrant     if (!xenbus->xsh) {
152094a2239SPaul Durrant         return;
153094a2239SPaul Durrant     }
154094a2239SPaul Durrant 
15582a29e30SPaul Durrant     qemu_set_fd_handler(xs_fileno(xenbus->xsh), NULL, NULL, NULL);
15682a29e30SPaul Durrant 
157094a2239SPaul Durrant     xs_close(xenbus->xsh);
158108f7bbaSPaul Durrant }
159108f7bbaSPaul Durrant 
16082a29e30SPaul Durrant static void xen_bus_watch(void *opaque)
16182a29e30SPaul Durrant {
16282a29e30SPaul Durrant     XenBus *xenbus = opaque;
16382a29e30SPaul Durrant     char **v;
16482a29e30SPaul Durrant     const char *token;
16582a29e30SPaul Durrant 
16682a29e30SPaul Durrant     g_assert(xenbus->xsh);
16782a29e30SPaul Durrant 
16882a29e30SPaul Durrant     v = xs_check_watch(xenbus->xsh);
16982a29e30SPaul Durrant     if (!v) {
17082a29e30SPaul Durrant         return;
17182a29e30SPaul Durrant     }
17282a29e30SPaul Durrant 
17382a29e30SPaul Durrant     token = v[XS_WATCH_TOKEN];
17482a29e30SPaul Durrant 
17582a29e30SPaul Durrant     trace_xen_bus_watch(token);
17682a29e30SPaul Durrant 
17782a29e30SPaul Durrant     notifier_list_notify(&xenbus->watch_notifiers, (void *)token);
17882a29e30SPaul Durrant 
17982a29e30SPaul Durrant     free(v);
18082a29e30SPaul Durrant }
18182a29e30SPaul Durrant 
182108f7bbaSPaul Durrant static void xen_bus_realize(BusState *bus, Error **errp)
183108f7bbaSPaul Durrant {
184094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(bus);
185094a2239SPaul Durrant     unsigned int domid;
186094a2239SPaul Durrant 
187108f7bbaSPaul Durrant     trace_xen_bus_realize();
188094a2239SPaul Durrant 
189094a2239SPaul Durrant     xenbus->xsh = xs_open(0);
190094a2239SPaul Durrant     if (!xenbus->xsh) {
191094a2239SPaul Durrant         error_setg_errno(errp, errno, "failed xs_open");
192094a2239SPaul Durrant         goto fail;
193094a2239SPaul Durrant     }
194094a2239SPaul Durrant 
195094a2239SPaul Durrant     if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */
196094a2239SPaul Durrant                       "domid", NULL, "%u", &domid) == 1) {
197094a2239SPaul Durrant         xenbus->backend_id = domid;
198094a2239SPaul Durrant     } else {
199094a2239SPaul Durrant         xenbus->backend_id = 0; /* Assume lack of node means dom0 */
200094a2239SPaul Durrant     }
201094a2239SPaul Durrant 
20282a29e30SPaul Durrant     notifier_list_init(&xenbus->watch_notifiers);
20382a29e30SPaul Durrant     qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL,
20482a29e30SPaul Durrant                         xenbus);
205094a2239SPaul Durrant     return;
206094a2239SPaul Durrant 
207094a2239SPaul Durrant fail:
208094a2239SPaul Durrant     xen_bus_unrealize(bus, &error_abort);
209108f7bbaSPaul Durrant }
210108f7bbaSPaul Durrant 
211108f7bbaSPaul Durrant static void xen_bus_class_init(ObjectClass *class, void *data)
212108f7bbaSPaul Durrant {
213108f7bbaSPaul Durrant     BusClass *bus_class = BUS_CLASS(class);
214108f7bbaSPaul Durrant 
215094a2239SPaul Durrant     bus_class->print_dev = xen_bus_print_dev;
216094a2239SPaul Durrant     bus_class->get_dev_path = xen_bus_get_dev_path;
217108f7bbaSPaul Durrant     bus_class->realize = xen_bus_realize;
218108f7bbaSPaul Durrant     bus_class->unrealize = xen_bus_unrealize;
219108f7bbaSPaul Durrant }
220108f7bbaSPaul Durrant 
221108f7bbaSPaul Durrant static const TypeInfo xen_bus_type_info = {
222108f7bbaSPaul Durrant     .name = TYPE_XEN_BUS,
223108f7bbaSPaul Durrant     .parent = TYPE_BUS,
224108f7bbaSPaul Durrant     .instance_size = sizeof(XenBus),
225108f7bbaSPaul Durrant     .class_size = sizeof(XenBusClass),
226108f7bbaSPaul Durrant     .class_init = xen_bus_class_init,
227108f7bbaSPaul Durrant     .interfaces = (InterfaceInfo[]) {
228108f7bbaSPaul Durrant         { TYPE_HOTPLUG_HANDLER },
229108f7bbaSPaul Durrant         { }
230108f7bbaSPaul Durrant     },
231108f7bbaSPaul Durrant };
232108f7bbaSPaul Durrant 
233094a2239SPaul Durrant static void xen_device_backend_printf(XenDevice *xendev, const char *key,
234094a2239SPaul Durrant                                       const char *fmt, ...)
235094a2239SPaul Durrant {
236094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
237094a2239SPaul Durrant     Error *local_err = NULL;
238094a2239SPaul Durrant     va_list ap;
239094a2239SPaul Durrant 
240094a2239SPaul Durrant     g_assert(xenbus->xsh);
241094a2239SPaul Durrant 
242094a2239SPaul Durrant     va_start(ap, fmt);
243094a2239SPaul Durrant     xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
244094a2239SPaul Durrant                     &local_err, fmt, ap);
245094a2239SPaul Durrant     va_end(ap);
246094a2239SPaul Durrant 
247094a2239SPaul Durrant     if (local_err) {
248094a2239SPaul Durrant         error_report_err(local_err);
249094a2239SPaul Durrant     }
250094a2239SPaul Durrant }
251094a2239SPaul Durrant 
25282a29e30SPaul Durrant static int xen_device_backend_scanf(XenDevice *xendev, const char *key,
25382a29e30SPaul Durrant                                     const char *fmt, ...)
25482a29e30SPaul Durrant {
25582a29e30SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
25682a29e30SPaul Durrant     va_list ap;
25782a29e30SPaul Durrant     int rc;
25882a29e30SPaul Durrant 
25982a29e30SPaul Durrant     g_assert(xenbus->xsh);
26082a29e30SPaul Durrant 
26182a29e30SPaul Durrant     va_start(ap, fmt);
26282a29e30SPaul Durrant     rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
26382a29e30SPaul Durrant                         NULL, fmt, ap);
26482a29e30SPaul Durrant     va_end(ap);
26582a29e30SPaul Durrant 
26682a29e30SPaul Durrant     return rc;
26782a29e30SPaul Durrant }
26882a29e30SPaul Durrant 
26982a29e30SPaul Durrant void xen_device_backend_set_state(XenDevice *xendev,
270094a2239SPaul Durrant                                   enum xenbus_state state)
271094a2239SPaul Durrant {
272094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
273094a2239SPaul Durrant 
274094a2239SPaul Durrant     if (xendev->backend_state == state) {
275094a2239SPaul Durrant         return;
276094a2239SPaul Durrant     }
277094a2239SPaul Durrant 
278094a2239SPaul Durrant     trace_xen_device_backend_state(type, xendev->name,
279094a2239SPaul Durrant                                    xs_strstate(state));
280094a2239SPaul Durrant 
281094a2239SPaul Durrant     xendev->backend_state = state;
282094a2239SPaul Durrant     xen_device_backend_printf(xendev, "state", "%u", state);
283094a2239SPaul Durrant }
284094a2239SPaul Durrant 
28582a29e30SPaul Durrant enum xenbus_state xen_device_backend_get_state(XenDevice *xendev)
28682a29e30SPaul Durrant {
28782a29e30SPaul Durrant     return xendev->backend_state;
28882a29e30SPaul Durrant }
28982a29e30SPaul Durrant 
290094a2239SPaul Durrant static void xen_device_backend_create(XenDevice *xendev, Error **errp)
291094a2239SPaul Durrant {
292094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
293094a2239SPaul Durrant     struct xs_permissions perms[2];
294094a2239SPaul Durrant     Error *local_err = NULL;
295094a2239SPaul Durrant 
296094a2239SPaul Durrant     xendev->backend_path = xen_device_get_backend_path(xendev);
297094a2239SPaul Durrant 
298094a2239SPaul Durrant     perms[0].id = xenbus->backend_id;
299094a2239SPaul Durrant     perms[0].perms = XS_PERM_NONE;
300094a2239SPaul Durrant     perms[1].id = xendev->frontend_id;
301094a2239SPaul Durrant     perms[1].perms = XS_PERM_READ;
302094a2239SPaul Durrant 
303094a2239SPaul Durrant     g_assert(xenbus->xsh);
304094a2239SPaul Durrant 
305094a2239SPaul Durrant     xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms,
306094a2239SPaul Durrant                    ARRAY_SIZE(perms), &local_err);
307094a2239SPaul Durrant     if (local_err) {
308094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
309094a2239SPaul Durrant                                 "failed to create backend: ");
310094a2239SPaul Durrant     }
311094a2239SPaul Durrant }
312094a2239SPaul Durrant 
313094a2239SPaul Durrant static void xen_device_backend_destroy(XenDevice *xendev)
314094a2239SPaul Durrant {
315094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
316094a2239SPaul Durrant     Error *local_err = NULL;
317094a2239SPaul Durrant 
318094a2239SPaul Durrant     if (!xendev->backend_path) {
319094a2239SPaul Durrant         return;
320094a2239SPaul Durrant     }
321094a2239SPaul Durrant 
322094a2239SPaul Durrant     g_assert(xenbus->xsh);
323094a2239SPaul Durrant 
324094a2239SPaul Durrant     xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path,
325094a2239SPaul Durrant                     &local_err);
326094a2239SPaul Durrant     g_free(xendev->backend_path);
327094a2239SPaul Durrant     xendev->backend_path = NULL;
328094a2239SPaul Durrant 
329094a2239SPaul Durrant     if (local_err) {
330094a2239SPaul Durrant         error_report_err(local_err);
331094a2239SPaul Durrant     }
332094a2239SPaul Durrant }
333094a2239SPaul Durrant 
334094a2239SPaul Durrant static void xen_device_frontend_printf(XenDevice *xendev, const char *key,
335094a2239SPaul Durrant                                        const char *fmt, ...)
336094a2239SPaul Durrant {
337094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
338094a2239SPaul Durrant     Error *local_err = NULL;
339094a2239SPaul Durrant     va_list ap;
340094a2239SPaul Durrant 
341094a2239SPaul Durrant     g_assert(xenbus->xsh);
342094a2239SPaul Durrant 
343094a2239SPaul Durrant     va_start(ap, fmt);
344094a2239SPaul Durrant     xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
345094a2239SPaul Durrant                     &local_err, fmt, ap);
346094a2239SPaul Durrant     va_end(ap);
347094a2239SPaul Durrant 
348094a2239SPaul Durrant     if (local_err) {
349094a2239SPaul Durrant         error_report_err(local_err);
350094a2239SPaul Durrant     }
351094a2239SPaul Durrant }
352094a2239SPaul Durrant 
35382a29e30SPaul Durrant static int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
35482a29e30SPaul Durrant                                      const char *fmt, ...)
35582a29e30SPaul Durrant {
35682a29e30SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
35782a29e30SPaul Durrant     va_list ap;
35882a29e30SPaul Durrant     int rc;
35982a29e30SPaul Durrant 
36082a29e30SPaul Durrant     g_assert(xenbus->xsh);
36182a29e30SPaul Durrant 
36282a29e30SPaul Durrant     va_start(ap, fmt);
36382a29e30SPaul Durrant     rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
36482a29e30SPaul Durrant                         NULL, fmt, ap);
36582a29e30SPaul Durrant     va_end(ap);
36682a29e30SPaul Durrant 
36782a29e30SPaul Durrant     return rc;
36882a29e30SPaul Durrant }
36982a29e30SPaul Durrant 
370094a2239SPaul Durrant static void xen_device_frontend_set_state(XenDevice *xendev,
371094a2239SPaul Durrant                                           enum xenbus_state state)
372094a2239SPaul Durrant {
373094a2239SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
374094a2239SPaul Durrant 
375094a2239SPaul Durrant     if (xendev->frontend_state == state) {
376094a2239SPaul Durrant         return;
377094a2239SPaul Durrant     }
378094a2239SPaul Durrant 
379094a2239SPaul Durrant     trace_xen_device_frontend_state(type, xendev->name,
380094a2239SPaul Durrant                                     xs_strstate(state));
381094a2239SPaul Durrant 
382094a2239SPaul Durrant     xendev->frontend_state = state;
383094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "state", "%u", state);
384094a2239SPaul Durrant }
385094a2239SPaul Durrant 
38682a29e30SPaul Durrant static void xen_device_frontend_changed(void *opaque)
38782a29e30SPaul Durrant {
38882a29e30SPaul Durrant     XenDevice *xendev = opaque;
38982a29e30SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
39082a29e30SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
39182a29e30SPaul Durrant     enum xenbus_state state;
39282a29e30SPaul Durrant 
39382a29e30SPaul Durrant     trace_xen_device_frontend_changed(type, xendev->name);
39482a29e30SPaul Durrant 
39582a29e30SPaul Durrant     if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) {
39682a29e30SPaul Durrant         state = XenbusStateUnknown;
39782a29e30SPaul Durrant     }
39882a29e30SPaul Durrant 
39982a29e30SPaul Durrant     xen_device_frontend_set_state(xendev, state);
40082a29e30SPaul Durrant 
40182a29e30SPaul Durrant     if (xendev_class->frontend_changed) {
40282a29e30SPaul Durrant         Error *local_err = NULL;
40382a29e30SPaul Durrant 
40482a29e30SPaul Durrant         xendev_class->frontend_changed(xendev, state, &local_err);
40582a29e30SPaul Durrant 
40682a29e30SPaul Durrant         if (local_err) {
40782a29e30SPaul Durrant             error_reportf_err(local_err, "frontend change error: ");
40882a29e30SPaul Durrant         }
40982a29e30SPaul Durrant     }
41082a29e30SPaul Durrant 
41182a29e30SPaul Durrant     /*
41282a29e30SPaul Durrant      * If a backend is still 'online' then its state should be cycled
41382a29e30SPaul Durrant      * back round to InitWait in order for a new frontend instance to
41482a29e30SPaul Durrant      * connect. This may happen when, for example, a frontend driver is
41582a29e30SPaul Durrant      * re-installed or updated.
41682a29e30SPaul Durrant      */
41782a29e30SPaul Durrant     if (xendev->backend_state == XenbusStateClosed) {
41882a29e30SPaul Durrant         unsigned int online;
41982a29e30SPaul Durrant 
42082a29e30SPaul Durrant         if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
42182a29e30SPaul Durrant             online = 0;
42282a29e30SPaul Durrant         }
42382a29e30SPaul Durrant 
42482a29e30SPaul Durrant         if (online) {
42582a29e30SPaul Durrant             xen_device_backend_set_state(xendev, XenbusStateInitWait);
42682a29e30SPaul Durrant         }
42782a29e30SPaul Durrant     }
42882a29e30SPaul Durrant }
42982a29e30SPaul Durrant 
430094a2239SPaul Durrant static void xen_device_frontend_create(XenDevice *xendev, Error **errp)
431094a2239SPaul Durrant {
432094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
433094a2239SPaul Durrant     struct xs_permissions perms[2];
434094a2239SPaul Durrant     Error *local_err = NULL;
435094a2239SPaul Durrant 
436094a2239SPaul Durrant     xendev->frontend_path = xen_device_get_frontend_path(xendev);
437094a2239SPaul Durrant 
438094a2239SPaul Durrant     perms[0].id = xendev->frontend_id;
439094a2239SPaul Durrant     perms[0].perms = XS_PERM_NONE;
440094a2239SPaul Durrant     perms[1].id = xenbus->backend_id;
441094a2239SPaul Durrant     perms[1].perms = XS_PERM_READ | XS_PERM_WRITE;
442094a2239SPaul Durrant 
443094a2239SPaul Durrant     g_assert(xenbus->xsh);
444094a2239SPaul Durrant 
445094a2239SPaul Durrant     xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms,
446094a2239SPaul Durrant                    ARRAY_SIZE(perms), &local_err);
447094a2239SPaul Durrant     if (local_err) {
448094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
449094a2239SPaul Durrant                                 "failed to create frontend: ");
45082a29e30SPaul Durrant         return;
45182a29e30SPaul Durrant     }
45282a29e30SPaul Durrant 
45382a29e30SPaul Durrant     xendev->frontend_state_watch =
45482a29e30SPaul Durrant         xen_bus_add_watch(xenbus, xendev->frontend_path, "state",
45582a29e30SPaul Durrant                           xen_device_frontend_changed, xendev, &local_err);
45682a29e30SPaul Durrant     if (local_err) {
45782a29e30SPaul Durrant         error_propagate_prepend(errp, local_err,
45882a29e30SPaul Durrant                                 "failed to watch frontend state: ");
459094a2239SPaul Durrant     }
460094a2239SPaul Durrant }
461094a2239SPaul Durrant 
462094a2239SPaul Durrant static void xen_device_frontend_destroy(XenDevice *xendev)
463094a2239SPaul Durrant {
464094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
465094a2239SPaul Durrant     Error *local_err = NULL;
466094a2239SPaul Durrant 
46782a29e30SPaul Durrant     if (xendev->frontend_state_watch) {
46882a29e30SPaul Durrant         xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL);
46982a29e30SPaul Durrant         xendev->frontend_state_watch = NULL;
47082a29e30SPaul Durrant     }
47182a29e30SPaul Durrant 
472094a2239SPaul Durrant     if (!xendev->frontend_path) {
473094a2239SPaul Durrant         return;
474094a2239SPaul Durrant     }
475094a2239SPaul Durrant 
476094a2239SPaul Durrant     g_assert(xenbus->xsh);
477094a2239SPaul Durrant 
478094a2239SPaul Durrant     xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path,
479094a2239SPaul Durrant                     &local_err);
480094a2239SPaul Durrant     g_free(xendev->frontend_path);
481094a2239SPaul Durrant     xendev->frontend_path = NULL;
482094a2239SPaul Durrant 
483094a2239SPaul Durrant     if (local_err) {
484094a2239SPaul Durrant         error_report_err(local_err);
485094a2239SPaul Durrant     }
486094a2239SPaul Durrant }
487094a2239SPaul Durrant 
4884b34b5b1SPaul Durrant void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs,
4894b34b5b1SPaul Durrant                                    Error **errp)
4904b34b5b1SPaul Durrant {
4914b34b5b1SPaul Durrant     if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) {
4924b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_set_max_grants failed");
4934b34b5b1SPaul Durrant     }
4944b34b5b1SPaul Durrant }
4954b34b5b1SPaul Durrant 
4964b34b5b1SPaul Durrant void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs,
4974b34b5b1SPaul Durrant                                 unsigned int nr_refs, int prot,
4984b34b5b1SPaul Durrant                                 Error **errp)
4994b34b5b1SPaul Durrant {
5004b34b5b1SPaul Durrant     void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs,
5014b34b5b1SPaul Durrant                                                 xendev->frontend_id, refs,
5024b34b5b1SPaul Durrant                                                 prot);
5034b34b5b1SPaul Durrant 
5044b34b5b1SPaul Durrant     if (!map) {
5054b34b5b1SPaul Durrant         error_setg_errno(errp, errno,
5064b34b5b1SPaul Durrant                          "xengnttab_map_domain_grant_refs failed");
5074b34b5b1SPaul Durrant     }
5084b34b5b1SPaul Durrant 
5094b34b5b1SPaul Durrant     return map;
5104b34b5b1SPaul Durrant }
5114b34b5b1SPaul Durrant 
5124b34b5b1SPaul Durrant void xen_device_unmap_grant_refs(XenDevice *xendev, void *map,
5134b34b5b1SPaul Durrant                                  unsigned int nr_refs, Error **errp)
5144b34b5b1SPaul Durrant {
5154b34b5b1SPaul Durrant     if (xengnttab_unmap(xendev->xgth, map, nr_refs)) {
5164b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_unmap failed");
5174b34b5b1SPaul Durrant     }
5184b34b5b1SPaul Durrant }
5194b34b5b1SPaul Durrant 
5204b34b5b1SPaul Durrant static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain,
5214b34b5b1SPaul Durrant                                    XenDeviceGrantCopySegment segs[],
5224b34b5b1SPaul Durrant                                    unsigned int nr_segs, Error **errp)
5234b34b5b1SPaul Durrant {
5244b34b5b1SPaul Durrant     uint32_t *refs = g_new(uint32_t, nr_segs);
5254b34b5b1SPaul Durrant     int prot = to_domain ? PROT_WRITE : PROT_READ;
5264b34b5b1SPaul Durrant     void *map;
5274b34b5b1SPaul Durrant     unsigned int i;
5284b34b5b1SPaul Durrant 
5294b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
5304b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
5314b34b5b1SPaul Durrant 
5324b34b5b1SPaul Durrant         refs[i] = to_domain ? seg->dest.foreign.ref :
5334b34b5b1SPaul Durrant             seg->source.foreign.ref;
5344b34b5b1SPaul Durrant     }
5354b34b5b1SPaul Durrant 
5364b34b5b1SPaul Durrant     map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs,
5374b34b5b1SPaul Durrant                                           xendev->frontend_id, refs,
5384b34b5b1SPaul Durrant                                           prot);
5394b34b5b1SPaul Durrant     if (!map) {
5404b34b5b1SPaul Durrant         error_setg_errno(errp, errno,
5414b34b5b1SPaul Durrant                          "xengnttab_map_domain_grant_refs failed");
5424b34b5b1SPaul Durrant         goto done;
5434b34b5b1SPaul Durrant     }
5444b34b5b1SPaul Durrant 
5454b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
5464b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
5474b34b5b1SPaul Durrant         void *page = map + (i * XC_PAGE_SIZE);
5484b34b5b1SPaul Durrant 
5494b34b5b1SPaul Durrant         if (to_domain) {
5504b34b5b1SPaul Durrant             memcpy(page + seg->dest.foreign.offset, seg->source.virt,
5514b34b5b1SPaul Durrant                    seg->len);
5524b34b5b1SPaul Durrant         } else {
5534b34b5b1SPaul Durrant             memcpy(seg->dest.virt, page + seg->source.foreign.offset,
5544b34b5b1SPaul Durrant                    seg->len);
5554b34b5b1SPaul Durrant         }
5564b34b5b1SPaul Durrant     }
5574b34b5b1SPaul Durrant 
5584b34b5b1SPaul Durrant     if (xengnttab_unmap(xendev->xgth, map, nr_segs)) {
5594b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_unmap failed");
5604b34b5b1SPaul Durrant     }
5614b34b5b1SPaul Durrant 
5624b34b5b1SPaul Durrant done:
5634b34b5b1SPaul Durrant     g_free(refs);
5644b34b5b1SPaul Durrant }
5654b34b5b1SPaul Durrant 
5664b34b5b1SPaul Durrant void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain,
5674b34b5b1SPaul Durrant                                 XenDeviceGrantCopySegment segs[],
5684b34b5b1SPaul Durrant                                 unsigned int nr_segs, Error **errp)
5694b34b5b1SPaul Durrant {
5704b34b5b1SPaul Durrant     xengnttab_grant_copy_segment_t *xengnttab_segs;
5714b34b5b1SPaul Durrant     unsigned int i;
5724b34b5b1SPaul Durrant 
5734b34b5b1SPaul Durrant     if (!xendev->feature_grant_copy) {
5744b34b5b1SPaul Durrant         compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp);
5754b34b5b1SPaul Durrant         return;
5764b34b5b1SPaul Durrant     }
5774b34b5b1SPaul Durrant 
5784b34b5b1SPaul Durrant     xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs);
5794b34b5b1SPaul Durrant 
5804b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
5814b34b5b1SPaul Durrant         XenDeviceGrantCopySegment *seg = &segs[i];
5824b34b5b1SPaul Durrant         xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
5834b34b5b1SPaul Durrant 
5844b34b5b1SPaul Durrant         if (to_domain) {
5854b34b5b1SPaul Durrant             xengnttab_seg->flags = GNTCOPY_dest_gref;
5864b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.domid = xendev->frontend_id;
5874b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref;
5884b34b5b1SPaul Durrant             xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset;
5894b34b5b1SPaul Durrant             xengnttab_seg->source.virt = seg->source.virt;
5904b34b5b1SPaul Durrant         } else {
5914b34b5b1SPaul Durrant             xengnttab_seg->flags = GNTCOPY_source_gref;
5924b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.domid = xendev->frontend_id;
5934b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.ref = seg->source.foreign.ref;
5944b34b5b1SPaul Durrant             xengnttab_seg->source.foreign.offset =
5954b34b5b1SPaul Durrant                 seg->source.foreign.offset;
5964b34b5b1SPaul Durrant             xengnttab_seg->dest.virt = seg->dest.virt;
5974b34b5b1SPaul Durrant         }
5984b34b5b1SPaul Durrant 
5994b34b5b1SPaul Durrant         xengnttab_seg->len = seg->len;
6004b34b5b1SPaul Durrant     }
6014b34b5b1SPaul Durrant 
6024b34b5b1SPaul Durrant     if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) {
6034b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "xengnttab_grant_copy failed");
6044b34b5b1SPaul Durrant         goto done;
6054b34b5b1SPaul Durrant     }
6064b34b5b1SPaul Durrant 
6074b34b5b1SPaul Durrant     for (i = 0; i < nr_segs; i++) {
6084b34b5b1SPaul Durrant         xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i];
6094b34b5b1SPaul Durrant 
6104b34b5b1SPaul Durrant         if (xengnttab_seg->status != GNTST_okay) {
6114b34b5b1SPaul Durrant             error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i);
6124b34b5b1SPaul Durrant             break;
6134b34b5b1SPaul Durrant         }
6144b34b5b1SPaul Durrant     }
6154b34b5b1SPaul Durrant 
6164b34b5b1SPaul Durrant done:
6174b34b5b1SPaul Durrant     g_free(xengnttab_segs);
6184b34b5b1SPaul Durrant }
6194b34b5b1SPaul Durrant 
620*a3d669c8SPaul Durrant struct XenEventChannel {
621*a3d669c8SPaul Durrant     evtchn_port_t local_port;
622*a3d669c8SPaul Durrant     XenEventHandler handler;
623*a3d669c8SPaul Durrant     void *opaque;
624*a3d669c8SPaul Durrant     Notifier notifier;
625*a3d669c8SPaul Durrant };
626*a3d669c8SPaul Durrant 
627*a3d669c8SPaul Durrant static void event_notify(Notifier *n, void *data)
628*a3d669c8SPaul Durrant {
629*a3d669c8SPaul Durrant     XenEventChannel *channel = container_of(n, XenEventChannel, notifier);
630*a3d669c8SPaul Durrant     unsigned long port = (unsigned long)data;
631*a3d669c8SPaul Durrant 
632*a3d669c8SPaul Durrant     if (port == channel->local_port) {
633*a3d669c8SPaul Durrant         channel->handler(channel->opaque);
634*a3d669c8SPaul Durrant     }
635*a3d669c8SPaul Durrant }
636*a3d669c8SPaul Durrant 
637*a3d669c8SPaul Durrant XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev,
638*a3d669c8SPaul Durrant                                                unsigned int port,
639*a3d669c8SPaul Durrant                                                XenEventHandler handler,
640*a3d669c8SPaul Durrant                                                void *opaque, Error **errp)
641*a3d669c8SPaul Durrant {
642*a3d669c8SPaul Durrant     XenEventChannel *channel = g_new0(XenEventChannel, 1);
643*a3d669c8SPaul Durrant     xenevtchn_port_or_error_t local_port;
644*a3d669c8SPaul Durrant 
645*a3d669c8SPaul Durrant     local_port = xenevtchn_bind_interdomain(xendev->xeh,
646*a3d669c8SPaul Durrant                                             xendev->frontend_id,
647*a3d669c8SPaul Durrant                                             port);
648*a3d669c8SPaul Durrant     if (local_port < 0) {
649*a3d669c8SPaul Durrant         error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed");
650*a3d669c8SPaul Durrant 
651*a3d669c8SPaul Durrant         g_free(channel);
652*a3d669c8SPaul Durrant         return NULL;
653*a3d669c8SPaul Durrant     }
654*a3d669c8SPaul Durrant 
655*a3d669c8SPaul Durrant     channel->local_port = local_port;
656*a3d669c8SPaul Durrant     channel->handler = handler;
657*a3d669c8SPaul Durrant     channel->opaque = opaque;
658*a3d669c8SPaul Durrant     channel->notifier.notify = event_notify;
659*a3d669c8SPaul Durrant 
660*a3d669c8SPaul Durrant     notifier_list_add(&xendev->event_notifiers, &channel->notifier);
661*a3d669c8SPaul Durrant 
662*a3d669c8SPaul Durrant     return channel;
663*a3d669c8SPaul Durrant }
664*a3d669c8SPaul Durrant 
665*a3d669c8SPaul Durrant void xen_device_notify_event_channel(XenDevice *xendev,
666*a3d669c8SPaul Durrant                                      XenEventChannel *channel,
667*a3d669c8SPaul Durrant                                      Error **errp)
668*a3d669c8SPaul Durrant {
669*a3d669c8SPaul Durrant     if (!channel) {
670*a3d669c8SPaul Durrant         error_setg(errp, "bad channel");
671*a3d669c8SPaul Durrant         return;
672*a3d669c8SPaul Durrant     }
673*a3d669c8SPaul Durrant 
674*a3d669c8SPaul Durrant     if (xenevtchn_notify(xendev->xeh, channel->local_port) < 0) {
675*a3d669c8SPaul Durrant         error_setg_errno(errp, errno, "xenevtchn_notify failed");
676*a3d669c8SPaul Durrant     }
677*a3d669c8SPaul Durrant }
678*a3d669c8SPaul Durrant 
679*a3d669c8SPaul Durrant void xen_device_unbind_event_channel(XenDevice *xendev,
680*a3d669c8SPaul Durrant                                      XenEventChannel *channel,
681*a3d669c8SPaul Durrant                                      Error **errp)
682*a3d669c8SPaul Durrant {
683*a3d669c8SPaul Durrant     if (!channel) {
684*a3d669c8SPaul Durrant         error_setg(errp, "bad channel");
685*a3d669c8SPaul Durrant         return;
686*a3d669c8SPaul Durrant     }
687*a3d669c8SPaul Durrant 
688*a3d669c8SPaul Durrant     notifier_remove(&channel->notifier);
689*a3d669c8SPaul Durrant 
690*a3d669c8SPaul Durrant     if (xenevtchn_unbind(xendev->xeh, channel->local_port) < 0) {
691*a3d669c8SPaul Durrant         error_setg_errno(errp, errno, "xenevtchn_unbind failed");
692*a3d669c8SPaul Durrant     }
693*a3d669c8SPaul Durrant 
694*a3d669c8SPaul Durrant     g_free(channel);
695*a3d669c8SPaul Durrant }
696*a3d669c8SPaul Durrant 
697108f7bbaSPaul Durrant static void xen_device_unrealize(DeviceState *dev, Error **errp)
698108f7bbaSPaul Durrant {
699108f7bbaSPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
700108f7bbaSPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
701108f7bbaSPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
702108f7bbaSPaul Durrant 
703094a2239SPaul Durrant     if (!xendev->name) {
704094a2239SPaul Durrant         return;
705094a2239SPaul Durrant     }
706094a2239SPaul Durrant 
707094a2239SPaul Durrant     trace_xen_device_unrealize(type, xendev->name);
708094a2239SPaul Durrant 
709094a2239SPaul Durrant     if (xendev->exit.notify) {
710094a2239SPaul Durrant         qemu_remove_exit_notifier(&xendev->exit);
711094a2239SPaul Durrant         xendev->exit.notify = NULL;
712094a2239SPaul Durrant     }
713108f7bbaSPaul Durrant 
714108f7bbaSPaul Durrant     if (xendev_class->unrealize) {
715108f7bbaSPaul Durrant         xendev_class->unrealize(xendev, errp);
716108f7bbaSPaul Durrant     }
717094a2239SPaul Durrant 
718094a2239SPaul Durrant     xen_device_frontend_destroy(xendev);
719094a2239SPaul Durrant     xen_device_backend_destroy(xendev);
720094a2239SPaul Durrant 
721*a3d669c8SPaul Durrant     if (xendev->xeh) {
722*a3d669c8SPaul Durrant         qemu_set_fd_handler(xenevtchn_fd(xendev->xeh), NULL, NULL, NULL);
723*a3d669c8SPaul Durrant         xenevtchn_close(xendev->xeh);
724*a3d669c8SPaul Durrant         xendev->xeh = NULL;
725*a3d669c8SPaul Durrant     }
726*a3d669c8SPaul Durrant 
7274b34b5b1SPaul Durrant     if (xendev->xgth) {
7284b34b5b1SPaul Durrant         xengnttab_close(xendev->xgth);
7294b34b5b1SPaul Durrant         xendev->xgth = NULL;
7304b34b5b1SPaul Durrant     }
7314b34b5b1SPaul Durrant 
732094a2239SPaul Durrant     g_free(xendev->name);
733094a2239SPaul Durrant     xendev->name = NULL;
734094a2239SPaul Durrant }
735094a2239SPaul Durrant 
736094a2239SPaul Durrant static void xen_device_exit(Notifier *n, void *data)
737094a2239SPaul Durrant {
738094a2239SPaul Durrant     XenDevice *xendev = container_of(n, XenDevice, exit);
739094a2239SPaul Durrant 
740094a2239SPaul Durrant     xen_device_unrealize(DEVICE(xendev), &error_abort);
741108f7bbaSPaul Durrant }
742108f7bbaSPaul Durrant 
743*a3d669c8SPaul Durrant static void xen_device_event(void *opaque)
744*a3d669c8SPaul Durrant {
745*a3d669c8SPaul Durrant     XenDevice *xendev = opaque;
746*a3d669c8SPaul Durrant     unsigned long port = xenevtchn_pending(xendev->xeh);
747*a3d669c8SPaul Durrant 
748*a3d669c8SPaul Durrant     notifier_list_notify(&xendev->event_notifiers, (void *)port);
749*a3d669c8SPaul Durrant 
750*a3d669c8SPaul Durrant     xenevtchn_unmask(xendev->xeh, port);
751*a3d669c8SPaul Durrant }
752*a3d669c8SPaul Durrant 
753108f7bbaSPaul Durrant static void xen_device_realize(DeviceState *dev, Error **errp)
754108f7bbaSPaul Durrant {
755108f7bbaSPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
756108f7bbaSPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
757094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
758108f7bbaSPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
759108f7bbaSPaul Durrant     Error *local_err = NULL;
760108f7bbaSPaul Durrant 
761094a2239SPaul Durrant     if (xendev->frontend_id == DOMID_INVALID) {
762094a2239SPaul Durrant         xendev->frontend_id = xen_domid;
763094a2239SPaul Durrant     }
764094a2239SPaul Durrant 
765094a2239SPaul Durrant     if (xendev->frontend_id >= DOMID_FIRST_RESERVED) {
766094a2239SPaul Durrant         error_setg(errp, "invalid frontend-id");
767094a2239SPaul Durrant         goto unrealize;
768094a2239SPaul Durrant     }
769094a2239SPaul Durrant 
770094a2239SPaul Durrant     if (!xendev_class->get_name) {
771094a2239SPaul Durrant         error_setg(errp, "get_name method not implemented");
772094a2239SPaul Durrant         goto unrealize;
773094a2239SPaul Durrant     }
774094a2239SPaul Durrant 
775094a2239SPaul Durrant     xendev->name = xendev_class->get_name(xendev, &local_err);
776094a2239SPaul Durrant     if (local_err) {
777094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
778094a2239SPaul Durrant                                 "failed to get device name: ");
779094a2239SPaul Durrant         goto unrealize;
780094a2239SPaul Durrant     }
781094a2239SPaul Durrant 
782094a2239SPaul Durrant     trace_xen_device_realize(type, xendev->name);
783094a2239SPaul Durrant 
7844b34b5b1SPaul Durrant     xendev->xgth = xengnttab_open(NULL, 0);
7854b34b5b1SPaul Durrant     if (!xendev->xgth) {
7864b34b5b1SPaul Durrant         error_setg_errno(errp, errno, "failed xengnttab_open");
7874b34b5b1SPaul Durrant         goto unrealize;
7884b34b5b1SPaul Durrant     }
7894b34b5b1SPaul Durrant 
7904b34b5b1SPaul Durrant     xendev->feature_grant_copy =
7914b34b5b1SPaul Durrant         (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0);
7924b34b5b1SPaul Durrant 
793*a3d669c8SPaul Durrant     xendev->xeh = xenevtchn_open(NULL, 0);
794*a3d669c8SPaul Durrant     if (!xendev->xeh) {
795*a3d669c8SPaul Durrant         error_setg_errno(errp, errno, "failed xenevtchn_open");
796*a3d669c8SPaul Durrant         goto unrealize;
797*a3d669c8SPaul Durrant     }
798*a3d669c8SPaul Durrant 
799*a3d669c8SPaul Durrant     notifier_list_init(&xendev->event_notifiers);
800*a3d669c8SPaul Durrant     qemu_set_fd_handler(xenevtchn_fd(xendev->xeh), xen_device_event, NULL,
801*a3d669c8SPaul Durrant                         xendev);
802*a3d669c8SPaul Durrant 
803094a2239SPaul Durrant     xen_device_backend_create(xendev, &local_err);
804094a2239SPaul Durrant     if (local_err) {
805094a2239SPaul Durrant         error_propagate(errp, local_err);
806094a2239SPaul Durrant         goto unrealize;
807094a2239SPaul Durrant     }
808094a2239SPaul Durrant 
809094a2239SPaul Durrant     xen_device_frontend_create(xendev, &local_err);
810094a2239SPaul Durrant     if (local_err) {
811094a2239SPaul Durrant         error_propagate(errp, local_err);
812094a2239SPaul Durrant         goto unrealize;
813094a2239SPaul Durrant     }
814108f7bbaSPaul Durrant 
815108f7bbaSPaul Durrant     if (xendev_class->realize) {
816108f7bbaSPaul Durrant         xendev_class->realize(xendev, &local_err);
817108f7bbaSPaul Durrant         if (local_err) {
818108f7bbaSPaul Durrant             error_propagate(errp, local_err);
819108f7bbaSPaul Durrant             goto unrealize;
820108f7bbaSPaul Durrant         }
821108f7bbaSPaul Durrant     }
822108f7bbaSPaul Durrant 
823094a2239SPaul Durrant     xen_device_backend_printf(xendev, "frontend", "%s",
824094a2239SPaul Durrant                               xendev->frontend_path);
825094a2239SPaul Durrant     xen_device_backend_printf(xendev, "frontend-id", "%u",
826094a2239SPaul Durrant                               xendev->frontend_id);
827094a2239SPaul Durrant     xen_device_backend_printf(xendev, "online", "%u", 1);
828094a2239SPaul Durrant     xen_device_backend_printf(xendev, "hotplug-status", "connected");
829094a2239SPaul Durrant 
830094a2239SPaul Durrant     xen_device_backend_set_state(xendev, XenbusStateInitWait);
831094a2239SPaul Durrant 
832094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "backend", "%s",
833094a2239SPaul Durrant                                xendev->backend_path);
834094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "backend-id", "%u",
835094a2239SPaul Durrant                                xenbus->backend_id);
836094a2239SPaul Durrant 
837094a2239SPaul Durrant     xen_device_frontend_set_state(xendev, XenbusStateInitialising);
838094a2239SPaul Durrant 
839094a2239SPaul Durrant     xendev->exit.notify = xen_device_exit;
840094a2239SPaul Durrant     qemu_add_exit_notifier(&xendev->exit);
841108f7bbaSPaul Durrant     return;
842108f7bbaSPaul Durrant 
843108f7bbaSPaul Durrant unrealize:
844108f7bbaSPaul Durrant     xen_device_unrealize(dev, &error_abort);
845108f7bbaSPaul Durrant }
846108f7bbaSPaul Durrant 
847094a2239SPaul Durrant static Property xen_device_props[] = {
848094a2239SPaul Durrant     DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
849094a2239SPaul Durrant                        DOMID_INVALID),
850094a2239SPaul Durrant     DEFINE_PROP_END_OF_LIST()
851094a2239SPaul Durrant };
852094a2239SPaul Durrant 
853108f7bbaSPaul Durrant static void xen_device_class_init(ObjectClass *class, void *data)
854108f7bbaSPaul Durrant {
855108f7bbaSPaul Durrant     DeviceClass *dev_class = DEVICE_CLASS(class);
856108f7bbaSPaul Durrant 
857108f7bbaSPaul Durrant     dev_class->realize = xen_device_realize;
858108f7bbaSPaul Durrant     dev_class->unrealize = xen_device_unrealize;
859094a2239SPaul Durrant     dev_class->props = xen_device_props;
860108f7bbaSPaul Durrant     dev_class->bus_type = TYPE_XEN_BUS;
861108f7bbaSPaul Durrant }
862108f7bbaSPaul Durrant 
863108f7bbaSPaul Durrant static const TypeInfo xen_device_type_info = {
864108f7bbaSPaul Durrant     .name = TYPE_XEN_DEVICE,
865108f7bbaSPaul Durrant     .parent = TYPE_DEVICE,
866108f7bbaSPaul Durrant     .instance_size = sizeof(XenDevice),
867108f7bbaSPaul Durrant     .abstract = true,
868108f7bbaSPaul Durrant     .class_size = sizeof(XenDeviceClass),
869108f7bbaSPaul Durrant     .class_init = xen_device_class_init,
870108f7bbaSPaul Durrant };
871108f7bbaSPaul Durrant 
872108f7bbaSPaul Durrant typedef struct XenBridge {
873108f7bbaSPaul Durrant     SysBusDevice busdev;
874108f7bbaSPaul Durrant } XenBridge;
875108f7bbaSPaul Durrant 
876108f7bbaSPaul Durrant #define TYPE_XEN_BRIDGE "xen-bridge"
877108f7bbaSPaul Durrant 
878108f7bbaSPaul Durrant static const TypeInfo xen_bridge_type_info = {
879108f7bbaSPaul Durrant     .name = TYPE_XEN_BRIDGE,
880108f7bbaSPaul Durrant     .parent = TYPE_SYS_BUS_DEVICE,
881108f7bbaSPaul Durrant     .instance_size = sizeof(XenBridge),
882108f7bbaSPaul Durrant };
883108f7bbaSPaul Durrant 
884108f7bbaSPaul Durrant static void xen_register_types(void)
885108f7bbaSPaul Durrant {
886108f7bbaSPaul Durrant     type_register_static(&xen_bridge_type_info);
887108f7bbaSPaul Durrant     type_register_static(&xen_bus_type_info);
888108f7bbaSPaul Durrant     type_register_static(&xen_device_type_info);
889108f7bbaSPaul Durrant }
890108f7bbaSPaul Durrant 
891108f7bbaSPaul Durrant type_init(xen_register_types)
892108f7bbaSPaul Durrant 
893108f7bbaSPaul Durrant void xen_bus_init(void)
894108f7bbaSPaul Durrant {
895108f7bbaSPaul Durrant     DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE);
896108f7bbaSPaul Durrant     BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL);
897108f7bbaSPaul Durrant 
898108f7bbaSPaul Durrant     qdev_init_nofail(dev);
899108f7bbaSPaul Durrant     qbus_set_bus_hotplug_handler(bus, &error_abort);
900108f7bbaSPaul Durrant }
901