xref: /openbmc/qemu/hw/xen/xen-bus.c (revision 82a29e304841e464ddb6a8a2c0240196b0ee3887)
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"
9*82a29e30SPaul Durrant #include "qemu/main-loop.h"
10*82a29e30SPaul 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 
64*82a29e30SPaul Durrant struct XenWatch {
65*82a29e30SPaul Durrant     char *node, *key;
66*82a29e30SPaul Durrant     char *token;
67*82a29e30SPaul Durrant     XenWatchHandler handler;
68*82a29e30SPaul Durrant     void *opaque;
69*82a29e30SPaul Durrant     Notifier notifier;
70*82a29e30SPaul Durrant };
71*82a29e30SPaul Durrant 
72*82a29e30SPaul Durrant static void watch_notify(Notifier *n, void *data)
73*82a29e30SPaul Durrant {
74*82a29e30SPaul Durrant     XenWatch *watch = container_of(n, XenWatch, notifier);
75*82a29e30SPaul Durrant     const char *token = data;
76*82a29e30SPaul Durrant 
77*82a29e30SPaul Durrant     if (!strcmp(watch->token, token)) {
78*82a29e30SPaul Durrant         watch->handler(watch->opaque);
79*82a29e30SPaul Durrant     }
80*82a29e30SPaul Durrant }
81*82a29e30SPaul Durrant 
82*82a29e30SPaul Durrant static XenWatch *new_watch(const char *node, const char *key,
83*82a29e30SPaul Durrant                            XenWatchHandler handler, void *opaque)
84*82a29e30SPaul Durrant {
85*82a29e30SPaul Durrant     XenWatch *watch = g_new0(XenWatch, 1);
86*82a29e30SPaul Durrant     QemuUUID uuid;
87*82a29e30SPaul Durrant 
88*82a29e30SPaul Durrant     qemu_uuid_generate(&uuid);
89*82a29e30SPaul Durrant 
90*82a29e30SPaul Durrant     watch->token = qemu_uuid_unparse_strdup(&uuid);
91*82a29e30SPaul Durrant     watch->node = g_strdup(node);
92*82a29e30SPaul Durrant     watch->key = g_strdup(key);
93*82a29e30SPaul Durrant     watch->handler = handler;
94*82a29e30SPaul Durrant     watch->opaque = opaque;
95*82a29e30SPaul Durrant     watch->notifier.notify = watch_notify;
96*82a29e30SPaul Durrant 
97*82a29e30SPaul Durrant     return watch;
98*82a29e30SPaul Durrant }
99*82a29e30SPaul Durrant 
100*82a29e30SPaul Durrant static void free_watch(XenWatch *watch)
101*82a29e30SPaul Durrant {
102*82a29e30SPaul Durrant     g_free(watch->token);
103*82a29e30SPaul Durrant     g_free(watch->key);
104*82a29e30SPaul Durrant     g_free(watch->node);
105*82a29e30SPaul Durrant 
106*82a29e30SPaul Durrant     g_free(watch);
107*82a29e30SPaul Durrant }
108*82a29e30SPaul Durrant 
109*82a29e30SPaul Durrant static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node,
110*82a29e30SPaul Durrant                                    const char *key, XenWatchHandler handler,
111*82a29e30SPaul Durrant                                    void *opaque, Error **errp)
112*82a29e30SPaul Durrant {
113*82a29e30SPaul Durrant     XenWatch *watch = new_watch(node, key, handler, opaque);
114*82a29e30SPaul Durrant     Error *local_err = NULL;
115*82a29e30SPaul Durrant 
116*82a29e30SPaul Durrant     trace_xen_bus_add_watch(watch->node, watch->key, watch->token);
117*82a29e30SPaul Durrant 
118*82a29e30SPaul Durrant     notifier_list_add(&xenbus->watch_notifiers, &watch->notifier);
119*82a29e30SPaul Durrant 
120*82a29e30SPaul Durrant     xs_node_watch(xenbus->xsh, node, key, watch->token, &local_err);
121*82a29e30SPaul Durrant     if (local_err) {
122*82a29e30SPaul Durrant         error_propagate(errp, local_err);
123*82a29e30SPaul Durrant 
124*82a29e30SPaul Durrant         notifier_remove(&watch->notifier);
125*82a29e30SPaul Durrant         free_watch(watch);
126*82a29e30SPaul Durrant 
127*82a29e30SPaul Durrant         return NULL;
128*82a29e30SPaul Durrant     }
129*82a29e30SPaul Durrant 
130*82a29e30SPaul Durrant     return watch;
131*82a29e30SPaul Durrant }
132*82a29e30SPaul Durrant 
133*82a29e30SPaul Durrant static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch,
134*82a29e30SPaul Durrant                                  Error **errp)
135*82a29e30SPaul Durrant {
136*82a29e30SPaul Durrant     trace_xen_bus_remove_watch(watch->node, watch->key, watch->token);
137*82a29e30SPaul Durrant 
138*82a29e30SPaul Durrant     xs_node_unwatch(xenbus->xsh, watch->node, watch->key, watch->token,
139*82a29e30SPaul Durrant                     errp);
140*82a29e30SPaul Durrant 
141*82a29e30SPaul Durrant     notifier_remove(&watch->notifier);
142*82a29e30SPaul Durrant     free_watch(watch);
143*82a29e30SPaul Durrant }
144*82a29e30SPaul 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 
155*82a29e30SPaul Durrant     qemu_set_fd_handler(xs_fileno(xenbus->xsh), NULL, NULL, NULL);
156*82a29e30SPaul Durrant 
157094a2239SPaul Durrant     xs_close(xenbus->xsh);
158108f7bbaSPaul Durrant }
159108f7bbaSPaul Durrant 
160*82a29e30SPaul Durrant static void xen_bus_watch(void *opaque)
161*82a29e30SPaul Durrant {
162*82a29e30SPaul Durrant     XenBus *xenbus = opaque;
163*82a29e30SPaul Durrant     char **v;
164*82a29e30SPaul Durrant     const char *token;
165*82a29e30SPaul Durrant 
166*82a29e30SPaul Durrant     g_assert(xenbus->xsh);
167*82a29e30SPaul Durrant 
168*82a29e30SPaul Durrant     v = xs_check_watch(xenbus->xsh);
169*82a29e30SPaul Durrant     if (!v) {
170*82a29e30SPaul Durrant         return;
171*82a29e30SPaul Durrant     }
172*82a29e30SPaul Durrant 
173*82a29e30SPaul Durrant     token = v[XS_WATCH_TOKEN];
174*82a29e30SPaul Durrant 
175*82a29e30SPaul Durrant     trace_xen_bus_watch(token);
176*82a29e30SPaul Durrant 
177*82a29e30SPaul Durrant     notifier_list_notify(&xenbus->watch_notifiers, (void *)token);
178*82a29e30SPaul Durrant 
179*82a29e30SPaul Durrant     free(v);
180*82a29e30SPaul Durrant }
181*82a29e30SPaul 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 
202*82a29e30SPaul Durrant     notifier_list_init(&xenbus->watch_notifiers);
203*82a29e30SPaul Durrant     qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL,
204*82a29e30SPaul 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 
252*82a29e30SPaul Durrant static int xen_device_backend_scanf(XenDevice *xendev, const char *key,
253*82a29e30SPaul Durrant                                     const char *fmt, ...)
254*82a29e30SPaul Durrant {
255*82a29e30SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
256*82a29e30SPaul Durrant     va_list ap;
257*82a29e30SPaul Durrant     int rc;
258*82a29e30SPaul Durrant 
259*82a29e30SPaul Durrant     g_assert(xenbus->xsh);
260*82a29e30SPaul Durrant 
261*82a29e30SPaul Durrant     va_start(ap, fmt);
262*82a29e30SPaul Durrant     rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key,
263*82a29e30SPaul Durrant                         NULL, fmt, ap);
264*82a29e30SPaul Durrant     va_end(ap);
265*82a29e30SPaul Durrant 
266*82a29e30SPaul Durrant     return rc;
267*82a29e30SPaul Durrant }
268*82a29e30SPaul Durrant 
269*82a29e30SPaul 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 
285*82a29e30SPaul Durrant enum xenbus_state xen_device_backend_get_state(XenDevice *xendev)
286*82a29e30SPaul Durrant {
287*82a29e30SPaul Durrant     return xendev->backend_state;
288*82a29e30SPaul Durrant }
289*82a29e30SPaul 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 
353*82a29e30SPaul Durrant static int xen_device_frontend_scanf(XenDevice *xendev, const char *key,
354*82a29e30SPaul Durrant                                      const char *fmt, ...)
355*82a29e30SPaul Durrant {
356*82a29e30SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
357*82a29e30SPaul Durrant     va_list ap;
358*82a29e30SPaul Durrant     int rc;
359*82a29e30SPaul Durrant 
360*82a29e30SPaul Durrant     g_assert(xenbus->xsh);
361*82a29e30SPaul Durrant 
362*82a29e30SPaul Durrant     va_start(ap, fmt);
363*82a29e30SPaul Durrant     rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key,
364*82a29e30SPaul Durrant                         NULL, fmt, ap);
365*82a29e30SPaul Durrant     va_end(ap);
366*82a29e30SPaul Durrant 
367*82a29e30SPaul Durrant     return rc;
368*82a29e30SPaul Durrant }
369*82a29e30SPaul 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 
386*82a29e30SPaul Durrant static void xen_device_frontend_changed(void *opaque)
387*82a29e30SPaul Durrant {
388*82a29e30SPaul Durrant     XenDevice *xendev = opaque;
389*82a29e30SPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
390*82a29e30SPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
391*82a29e30SPaul Durrant     enum xenbus_state state;
392*82a29e30SPaul Durrant 
393*82a29e30SPaul Durrant     trace_xen_device_frontend_changed(type, xendev->name);
394*82a29e30SPaul Durrant 
395*82a29e30SPaul Durrant     if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) {
396*82a29e30SPaul Durrant         state = XenbusStateUnknown;
397*82a29e30SPaul Durrant     }
398*82a29e30SPaul Durrant 
399*82a29e30SPaul Durrant     xen_device_frontend_set_state(xendev, state);
400*82a29e30SPaul Durrant 
401*82a29e30SPaul Durrant     if (xendev_class->frontend_changed) {
402*82a29e30SPaul Durrant         Error *local_err = NULL;
403*82a29e30SPaul Durrant 
404*82a29e30SPaul Durrant         xendev_class->frontend_changed(xendev, state, &local_err);
405*82a29e30SPaul Durrant 
406*82a29e30SPaul Durrant         if (local_err) {
407*82a29e30SPaul Durrant             error_reportf_err(local_err, "frontend change error: ");
408*82a29e30SPaul Durrant         }
409*82a29e30SPaul Durrant     }
410*82a29e30SPaul Durrant 
411*82a29e30SPaul Durrant     /*
412*82a29e30SPaul Durrant      * If a backend is still 'online' then its state should be cycled
413*82a29e30SPaul Durrant      * back round to InitWait in order for a new frontend instance to
414*82a29e30SPaul Durrant      * connect. This may happen when, for example, a frontend driver is
415*82a29e30SPaul Durrant      * re-installed or updated.
416*82a29e30SPaul Durrant      */
417*82a29e30SPaul Durrant     if (xendev->backend_state == XenbusStateClosed) {
418*82a29e30SPaul Durrant         unsigned int online;
419*82a29e30SPaul Durrant 
420*82a29e30SPaul Durrant         if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) {
421*82a29e30SPaul Durrant             online = 0;
422*82a29e30SPaul Durrant         }
423*82a29e30SPaul Durrant 
424*82a29e30SPaul Durrant         if (online) {
425*82a29e30SPaul Durrant             xen_device_backend_set_state(xendev, XenbusStateInitWait);
426*82a29e30SPaul Durrant         }
427*82a29e30SPaul Durrant     }
428*82a29e30SPaul Durrant }
429*82a29e30SPaul 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: ");
450*82a29e30SPaul Durrant         return;
451*82a29e30SPaul Durrant     }
452*82a29e30SPaul Durrant 
453*82a29e30SPaul Durrant     xendev->frontend_state_watch =
454*82a29e30SPaul Durrant         xen_bus_add_watch(xenbus, xendev->frontend_path, "state",
455*82a29e30SPaul Durrant                           xen_device_frontend_changed, xendev, &local_err);
456*82a29e30SPaul Durrant     if (local_err) {
457*82a29e30SPaul Durrant         error_propagate_prepend(errp, local_err,
458*82a29e30SPaul 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 
467*82a29e30SPaul Durrant     if (xendev->frontend_state_watch) {
468*82a29e30SPaul Durrant         xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL);
469*82a29e30SPaul Durrant         xendev->frontend_state_watch = NULL;
470*82a29e30SPaul Durrant     }
471*82a29e30SPaul 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 
488108f7bbaSPaul Durrant static void xen_device_unrealize(DeviceState *dev, Error **errp)
489108f7bbaSPaul Durrant {
490108f7bbaSPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
491108f7bbaSPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
492108f7bbaSPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
493108f7bbaSPaul Durrant 
494094a2239SPaul Durrant     if (!xendev->name) {
495094a2239SPaul Durrant         return;
496094a2239SPaul Durrant     }
497094a2239SPaul Durrant 
498094a2239SPaul Durrant     trace_xen_device_unrealize(type, xendev->name);
499094a2239SPaul Durrant 
500094a2239SPaul Durrant     if (xendev->exit.notify) {
501094a2239SPaul Durrant         qemu_remove_exit_notifier(&xendev->exit);
502094a2239SPaul Durrant         xendev->exit.notify = NULL;
503094a2239SPaul Durrant     }
504108f7bbaSPaul Durrant 
505108f7bbaSPaul Durrant     if (xendev_class->unrealize) {
506108f7bbaSPaul Durrant         xendev_class->unrealize(xendev, errp);
507108f7bbaSPaul Durrant     }
508094a2239SPaul Durrant 
509094a2239SPaul Durrant     xen_device_frontend_destroy(xendev);
510094a2239SPaul Durrant     xen_device_backend_destroy(xendev);
511094a2239SPaul Durrant 
512094a2239SPaul Durrant     g_free(xendev->name);
513094a2239SPaul Durrant     xendev->name = NULL;
514094a2239SPaul Durrant }
515094a2239SPaul Durrant 
516094a2239SPaul Durrant static void xen_device_exit(Notifier *n, void *data)
517094a2239SPaul Durrant {
518094a2239SPaul Durrant     XenDevice *xendev = container_of(n, XenDevice, exit);
519094a2239SPaul Durrant 
520094a2239SPaul Durrant     xen_device_unrealize(DEVICE(xendev), &error_abort);
521108f7bbaSPaul Durrant }
522108f7bbaSPaul Durrant 
523108f7bbaSPaul Durrant static void xen_device_realize(DeviceState *dev, Error **errp)
524108f7bbaSPaul Durrant {
525108f7bbaSPaul Durrant     XenDevice *xendev = XEN_DEVICE(dev);
526108f7bbaSPaul Durrant     XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev);
527094a2239SPaul Durrant     XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev)));
528108f7bbaSPaul Durrant     const char *type = object_get_typename(OBJECT(xendev));
529108f7bbaSPaul Durrant     Error *local_err = NULL;
530108f7bbaSPaul Durrant 
531094a2239SPaul Durrant     if (xendev->frontend_id == DOMID_INVALID) {
532094a2239SPaul Durrant         xendev->frontend_id = xen_domid;
533094a2239SPaul Durrant     }
534094a2239SPaul Durrant 
535094a2239SPaul Durrant     if (xendev->frontend_id >= DOMID_FIRST_RESERVED) {
536094a2239SPaul Durrant         error_setg(errp, "invalid frontend-id");
537094a2239SPaul Durrant         goto unrealize;
538094a2239SPaul Durrant     }
539094a2239SPaul Durrant 
540094a2239SPaul Durrant     if (!xendev_class->get_name) {
541094a2239SPaul Durrant         error_setg(errp, "get_name method not implemented");
542094a2239SPaul Durrant         goto unrealize;
543094a2239SPaul Durrant     }
544094a2239SPaul Durrant 
545094a2239SPaul Durrant     xendev->name = xendev_class->get_name(xendev, &local_err);
546094a2239SPaul Durrant     if (local_err) {
547094a2239SPaul Durrant         error_propagate_prepend(errp, local_err,
548094a2239SPaul Durrant                                 "failed to get device name: ");
549094a2239SPaul Durrant         goto unrealize;
550094a2239SPaul Durrant     }
551094a2239SPaul Durrant 
552094a2239SPaul Durrant     trace_xen_device_realize(type, xendev->name);
553094a2239SPaul Durrant 
554094a2239SPaul Durrant     xen_device_backend_create(xendev, &local_err);
555094a2239SPaul Durrant     if (local_err) {
556094a2239SPaul Durrant         error_propagate(errp, local_err);
557094a2239SPaul Durrant         goto unrealize;
558094a2239SPaul Durrant     }
559094a2239SPaul Durrant 
560094a2239SPaul Durrant     xen_device_frontend_create(xendev, &local_err);
561094a2239SPaul Durrant     if (local_err) {
562094a2239SPaul Durrant         error_propagate(errp, local_err);
563094a2239SPaul Durrant         goto unrealize;
564094a2239SPaul Durrant     }
565108f7bbaSPaul Durrant 
566108f7bbaSPaul Durrant     if (xendev_class->realize) {
567108f7bbaSPaul Durrant         xendev_class->realize(xendev, &local_err);
568108f7bbaSPaul Durrant         if (local_err) {
569108f7bbaSPaul Durrant             error_propagate(errp, local_err);
570108f7bbaSPaul Durrant             goto unrealize;
571108f7bbaSPaul Durrant         }
572108f7bbaSPaul Durrant     }
573108f7bbaSPaul Durrant 
574094a2239SPaul Durrant     xen_device_backend_printf(xendev, "frontend", "%s",
575094a2239SPaul Durrant                               xendev->frontend_path);
576094a2239SPaul Durrant     xen_device_backend_printf(xendev, "frontend-id", "%u",
577094a2239SPaul Durrant                               xendev->frontend_id);
578094a2239SPaul Durrant     xen_device_backend_printf(xendev, "online", "%u", 1);
579094a2239SPaul Durrant     xen_device_backend_printf(xendev, "hotplug-status", "connected");
580094a2239SPaul Durrant 
581094a2239SPaul Durrant     xen_device_backend_set_state(xendev, XenbusStateInitWait);
582094a2239SPaul Durrant 
583094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "backend", "%s",
584094a2239SPaul Durrant                                xendev->backend_path);
585094a2239SPaul Durrant     xen_device_frontend_printf(xendev, "backend-id", "%u",
586094a2239SPaul Durrant                                xenbus->backend_id);
587094a2239SPaul Durrant 
588094a2239SPaul Durrant     xen_device_frontend_set_state(xendev, XenbusStateInitialising);
589094a2239SPaul Durrant 
590094a2239SPaul Durrant     xendev->exit.notify = xen_device_exit;
591094a2239SPaul Durrant     qemu_add_exit_notifier(&xendev->exit);
592108f7bbaSPaul Durrant     return;
593108f7bbaSPaul Durrant 
594108f7bbaSPaul Durrant unrealize:
595108f7bbaSPaul Durrant     xen_device_unrealize(dev, &error_abort);
596108f7bbaSPaul Durrant }
597108f7bbaSPaul Durrant 
598094a2239SPaul Durrant static Property xen_device_props[] = {
599094a2239SPaul Durrant     DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id,
600094a2239SPaul Durrant                        DOMID_INVALID),
601094a2239SPaul Durrant     DEFINE_PROP_END_OF_LIST()
602094a2239SPaul Durrant };
603094a2239SPaul Durrant 
604108f7bbaSPaul Durrant static void xen_device_class_init(ObjectClass *class, void *data)
605108f7bbaSPaul Durrant {
606108f7bbaSPaul Durrant     DeviceClass *dev_class = DEVICE_CLASS(class);
607108f7bbaSPaul Durrant 
608108f7bbaSPaul Durrant     dev_class->realize = xen_device_realize;
609108f7bbaSPaul Durrant     dev_class->unrealize = xen_device_unrealize;
610094a2239SPaul Durrant     dev_class->props = xen_device_props;
611108f7bbaSPaul Durrant     dev_class->bus_type = TYPE_XEN_BUS;
612108f7bbaSPaul Durrant }
613108f7bbaSPaul Durrant 
614108f7bbaSPaul Durrant static const TypeInfo xen_device_type_info = {
615108f7bbaSPaul Durrant     .name = TYPE_XEN_DEVICE,
616108f7bbaSPaul Durrant     .parent = TYPE_DEVICE,
617108f7bbaSPaul Durrant     .instance_size = sizeof(XenDevice),
618108f7bbaSPaul Durrant     .abstract = true,
619108f7bbaSPaul Durrant     .class_size = sizeof(XenDeviceClass),
620108f7bbaSPaul Durrant     .class_init = xen_device_class_init,
621108f7bbaSPaul Durrant };
622108f7bbaSPaul Durrant 
623108f7bbaSPaul Durrant typedef struct XenBridge {
624108f7bbaSPaul Durrant     SysBusDevice busdev;
625108f7bbaSPaul Durrant } XenBridge;
626108f7bbaSPaul Durrant 
627108f7bbaSPaul Durrant #define TYPE_XEN_BRIDGE "xen-bridge"
628108f7bbaSPaul Durrant 
629108f7bbaSPaul Durrant static const TypeInfo xen_bridge_type_info = {
630108f7bbaSPaul Durrant     .name = TYPE_XEN_BRIDGE,
631108f7bbaSPaul Durrant     .parent = TYPE_SYS_BUS_DEVICE,
632108f7bbaSPaul Durrant     .instance_size = sizeof(XenBridge),
633108f7bbaSPaul Durrant };
634108f7bbaSPaul Durrant 
635108f7bbaSPaul Durrant static void xen_register_types(void)
636108f7bbaSPaul Durrant {
637108f7bbaSPaul Durrant     type_register_static(&xen_bridge_type_info);
638108f7bbaSPaul Durrant     type_register_static(&xen_bus_type_info);
639108f7bbaSPaul Durrant     type_register_static(&xen_device_type_info);
640108f7bbaSPaul Durrant }
641108f7bbaSPaul Durrant 
642108f7bbaSPaul Durrant type_init(xen_register_types)
643108f7bbaSPaul Durrant 
644108f7bbaSPaul Durrant void xen_bus_init(void)
645108f7bbaSPaul Durrant {
646108f7bbaSPaul Durrant     DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE);
647108f7bbaSPaul Durrant     BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL);
648108f7bbaSPaul Durrant 
649108f7bbaSPaul Durrant     qdev_init_nofail(dev);
650108f7bbaSPaul Durrant     qbus_set_bus_hotplug_handler(bus, &error_abort);
651108f7bbaSPaul Durrant }
652