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