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