1108f7bbaSPaul Durrant /* 2108f7bbaSPaul Durrant * Copyright (c) 2018 Citrix Systems Inc. 3108f7bbaSPaul Durrant * 4108f7bbaSPaul Durrant * This work is licensed under the terms of the GNU GPL, version 2 or later. 5108f7bbaSPaul Durrant * See the COPYING file in the top-level directory. 6108f7bbaSPaul Durrant */ 7108f7bbaSPaul Durrant 8108f7bbaSPaul Durrant #include "qemu/osdep.h" 982a29e30SPaul Durrant #include "qemu/main-loop.h" 100b8fa32fSMarkus Armbruster #include "qemu/module.h" 1182a29e30SPaul Durrant #include "qemu/uuid.h" 12a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 13108f7bbaSPaul Durrant #include "hw/sysbus.h" 14094a2239SPaul Durrant #include "hw/xen/xen.h" 15a783f8adSPaul Durrant #include "hw/xen/xen-backend.h" 16108f7bbaSPaul Durrant #include "hw/xen/xen-bus.h" 17094a2239SPaul Durrant #include "hw/xen/xen-bus-helper.h" 18094a2239SPaul Durrant #include "monitor/monitor.h" 19108f7bbaSPaul Durrant #include "qapi/error.h" 20a783f8adSPaul Durrant #include "qapi/qmp/qdict.h" 21094a2239SPaul Durrant #include "sysemu/sysemu.h" 22108f7bbaSPaul Durrant #include "trace.h" 23108f7bbaSPaul Durrant 24094a2239SPaul Durrant static char *xen_device_get_backend_path(XenDevice *xendev) 25094a2239SPaul Durrant { 26094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 27094a2239SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 28094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 29094a2239SPaul Durrant const char *backend = xendev_class->backend; 30094a2239SPaul Durrant 31094a2239SPaul Durrant if (!backend) { 32094a2239SPaul Durrant backend = type; 33094a2239SPaul Durrant } 34094a2239SPaul Durrant 35094a2239SPaul Durrant return g_strdup_printf("/local/domain/%u/backend/%s/%u/%s", 36094a2239SPaul Durrant xenbus->backend_id, backend, xendev->frontend_id, 37094a2239SPaul Durrant xendev->name); 38094a2239SPaul Durrant } 39094a2239SPaul Durrant 40094a2239SPaul Durrant static char *xen_device_get_frontend_path(XenDevice *xendev) 41094a2239SPaul Durrant { 42094a2239SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 43094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 44094a2239SPaul Durrant const char *device = xendev_class->device; 45094a2239SPaul Durrant 46094a2239SPaul Durrant if (!device) { 47094a2239SPaul Durrant device = type; 48094a2239SPaul Durrant } 49094a2239SPaul Durrant 50094a2239SPaul Durrant return g_strdup_printf("/local/domain/%u/device/%s/%s", 51094a2239SPaul Durrant xendev->frontend_id, device, xendev->name); 52094a2239SPaul Durrant } 53094a2239SPaul Durrant 54b6af8926SPaul Durrant static void xen_device_unplug(XenDevice *xendev, Error **errp) 55b6af8926SPaul Durrant { 56b6af8926SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 57b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 58b6af8926SPaul Durrant Error *local_err = NULL; 59b6af8926SPaul Durrant xs_transaction_t tid; 60b6af8926SPaul Durrant 61b6af8926SPaul Durrant trace_xen_device_unplug(type, xendev->name); 62b6af8926SPaul Durrant 63b6af8926SPaul Durrant /* Mimic the way the Xen toolstack does an unplug */ 64b6af8926SPaul Durrant again: 65b6af8926SPaul Durrant tid = xs_transaction_start(xenbus->xsh); 66b6af8926SPaul Durrant if (tid == XBT_NULL) { 67b6af8926SPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_start"); 68b6af8926SPaul Durrant return; 69b6af8926SPaul Durrant } 70b6af8926SPaul Durrant 71b6af8926SPaul Durrant xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "online", 72b6af8926SPaul Durrant &local_err, "%u", 0); 73b6af8926SPaul Durrant if (local_err) { 74b6af8926SPaul Durrant goto abort; 75b6af8926SPaul Durrant } 76b6af8926SPaul Durrant 77b6af8926SPaul Durrant xs_node_printf(xenbus->xsh, tid, xendev->backend_path, "state", 78b6af8926SPaul Durrant &local_err, "%u", XenbusStateClosing); 79b6af8926SPaul Durrant if (local_err) { 80b6af8926SPaul Durrant goto abort; 81b6af8926SPaul Durrant } 82b6af8926SPaul Durrant 83b6af8926SPaul Durrant if (!xs_transaction_end(xenbus->xsh, tid, false)) { 84b6af8926SPaul Durrant if (errno == EAGAIN) { 85b6af8926SPaul Durrant goto again; 86b6af8926SPaul Durrant } 87b6af8926SPaul Durrant 88b6af8926SPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end"); 89b6af8926SPaul Durrant } 90b6af8926SPaul Durrant 91b6af8926SPaul Durrant return; 92b6af8926SPaul Durrant 93b6af8926SPaul Durrant abort: 94b6af8926SPaul Durrant /* 95b6af8926SPaul Durrant * We only abort if there is already a failure so ignore any error 96b6af8926SPaul Durrant * from ending the transaction. 97b6af8926SPaul Durrant */ 98b6af8926SPaul Durrant xs_transaction_end(xenbus->xsh, tid, true); 99b6af8926SPaul Durrant error_propagate(errp, local_err); 100b6af8926SPaul Durrant } 101b6af8926SPaul Durrant 102094a2239SPaul Durrant static void xen_bus_print_dev(Monitor *mon, DeviceState *dev, int indent) 103094a2239SPaul Durrant { 104094a2239SPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 105094a2239SPaul Durrant 106094a2239SPaul Durrant monitor_printf(mon, "%*sname = '%s' frontend_id = %u\n", 107094a2239SPaul Durrant indent, "", xendev->name, xendev->frontend_id); 108094a2239SPaul Durrant } 109094a2239SPaul Durrant 110094a2239SPaul Durrant static char *xen_bus_get_dev_path(DeviceState *dev) 111094a2239SPaul Durrant { 112094a2239SPaul Durrant return xen_device_get_backend_path(XEN_DEVICE(dev)); 113094a2239SPaul Durrant } 114094a2239SPaul Durrant 11582a29e30SPaul Durrant struct XenWatch { 11682a29e30SPaul Durrant char *node, *key; 11782a29e30SPaul Durrant char *token; 11882a29e30SPaul Durrant XenWatchHandler handler; 11982a29e30SPaul Durrant void *opaque; 12082a29e30SPaul Durrant Notifier notifier; 12182a29e30SPaul Durrant }; 12282a29e30SPaul Durrant 12382a29e30SPaul Durrant static void watch_notify(Notifier *n, void *data) 12482a29e30SPaul Durrant { 12582a29e30SPaul Durrant XenWatch *watch = container_of(n, XenWatch, notifier); 12682a29e30SPaul Durrant const char *token = data; 12782a29e30SPaul Durrant 12882a29e30SPaul Durrant if (!strcmp(watch->token, token)) { 12982a29e30SPaul Durrant watch->handler(watch->opaque); 13082a29e30SPaul Durrant } 13182a29e30SPaul Durrant } 13282a29e30SPaul Durrant 13382a29e30SPaul Durrant static XenWatch *new_watch(const char *node, const char *key, 13482a29e30SPaul Durrant XenWatchHandler handler, void *opaque) 13582a29e30SPaul Durrant { 13682a29e30SPaul Durrant XenWatch *watch = g_new0(XenWatch, 1); 13782a29e30SPaul Durrant QemuUUID uuid; 13882a29e30SPaul Durrant 13982a29e30SPaul Durrant qemu_uuid_generate(&uuid); 14082a29e30SPaul Durrant 14182a29e30SPaul Durrant watch->token = qemu_uuid_unparse_strdup(&uuid); 14282a29e30SPaul Durrant watch->node = g_strdup(node); 14382a29e30SPaul Durrant watch->key = g_strdup(key); 14482a29e30SPaul Durrant watch->handler = handler; 14582a29e30SPaul Durrant watch->opaque = opaque; 14682a29e30SPaul Durrant watch->notifier.notify = watch_notify; 14782a29e30SPaul Durrant 14882a29e30SPaul Durrant return watch; 14982a29e30SPaul Durrant } 15082a29e30SPaul Durrant 15182a29e30SPaul Durrant static void free_watch(XenWatch *watch) 15282a29e30SPaul Durrant { 15382a29e30SPaul Durrant g_free(watch->token); 15482a29e30SPaul Durrant g_free(watch->key); 15582a29e30SPaul Durrant g_free(watch->node); 15682a29e30SPaul Durrant 15782a29e30SPaul Durrant g_free(watch); 15882a29e30SPaul Durrant } 15982a29e30SPaul Durrant 16082a29e30SPaul Durrant static XenWatch *xen_bus_add_watch(XenBus *xenbus, const char *node, 16182a29e30SPaul Durrant const char *key, XenWatchHandler handler, 16282a29e30SPaul Durrant void *opaque, Error **errp) 16382a29e30SPaul Durrant { 16482a29e30SPaul Durrant XenWatch *watch = new_watch(node, key, handler, opaque); 16582a29e30SPaul Durrant Error *local_err = NULL; 16682a29e30SPaul Durrant 16782a29e30SPaul Durrant trace_xen_bus_add_watch(watch->node, watch->key, watch->token); 16882a29e30SPaul Durrant 16982a29e30SPaul Durrant notifier_list_add(&xenbus->watch_notifiers, &watch->notifier); 17082a29e30SPaul Durrant 17182a29e30SPaul Durrant xs_node_watch(xenbus->xsh, node, key, watch->token, &local_err); 17282a29e30SPaul Durrant if (local_err) { 17382a29e30SPaul Durrant error_propagate(errp, local_err); 17482a29e30SPaul Durrant 17582a29e30SPaul Durrant notifier_remove(&watch->notifier); 17682a29e30SPaul Durrant free_watch(watch); 17782a29e30SPaul Durrant 17882a29e30SPaul Durrant return NULL; 17982a29e30SPaul Durrant } 18082a29e30SPaul Durrant 18182a29e30SPaul Durrant return watch; 18282a29e30SPaul Durrant } 18382a29e30SPaul Durrant 18482a29e30SPaul Durrant static void xen_bus_remove_watch(XenBus *xenbus, XenWatch *watch, 18582a29e30SPaul Durrant Error **errp) 18682a29e30SPaul Durrant { 18782a29e30SPaul Durrant trace_xen_bus_remove_watch(watch->node, watch->key, watch->token); 18882a29e30SPaul Durrant 18982a29e30SPaul Durrant xs_node_unwatch(xenbus->xsh, watch->node, watch->key, watch->token, 19082a29e30SPaul Durrant errp); 19182a29e30SPaul Durrant 19282a29e30SPaul Durrant notifier_remove(&watch->notifier); 19382a29e30SPaul Durrant free_watch(watch); 19482a29e30SPaul Durrant } 19582a29e30SPaul Durrant 196a783f8adSPaul Durrant static void xen_bus_backend_create(XenBus *xenbus, const char *type, 197a783f8adSPaul Durrant const char *name, char *path, 198a783f8adSPaul Durrant Error **errp) 199a783f8adSPaul Durrant { 200a783f8adSPaul Durrant xs_transaction_t tid; 201a783f8adSPaul Durrant char **key; 202a783f8adSPaul Durrant QDict *opts; 203a783f8adSPaul Durrant unsigned int i, n; 204a783f8adSPaul Durrant Error *local_err = NULL; 205a783f8adSPaul Durrant 206a783f8adSPaul Durrant trace_xen_bus_backend_create(type, path); 207a783f8adSPaul Durrant 208a783f8adSPaul Durrant again: 209a783f8adSPaul Durrant tid = xs_transaction_start(xenbus->xsh); 210a783f8adSPaul Durrant if (tid == XBT_NULL) { 211a783f8adSPaul Durrant error_setg(errp, "failed xs_transaction_start"); 212a783f8adSPaul Durrant return; 213a783f8adSPaul Durrant } 214a783f8adSPaul Durrant 215a783f8adSPaul Durrant key = xs_directory(xenbus->xsh, tid, path, &n); 216a783f8adSPaul Durrant if (!key) { 217a783f8adSPaul Durrant if (!xs_transaction_end(xenbus->xsh, tid, true)) { 218a783f8adSPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end"); 219a783f8adSPaul Durrant } 220a783f8adSPaul Durrant return; 221a783f8adSPaul Durrant } 222a783f8adSPaul Durrant 223a783f8adSPaul Durrant opts = qdict_new(); 224a783f8adSPaul Durrant for (i = 0; i < n; i++) { 225a783f8adSPaul Durrant char *val; 226a783f8adSPaul Durrant 227a783f8adSPaul Durrant /* 228a783f8adSPaul Durrant * Assume anything found in the xenstore backend area, other than 229a783f8adSPaul Durrant * the keys created for a generic XenDevice, are parameters 230a783f8adSPaul Durrant * to be used to configure the backend. 231a783f8adSPaul Durrant */ 232a783f8adSPaul Durrant if (!strcmp(key[i], "state") || 233a783f8adSPaul Durrant !strcmp(key[i], "online") || 234a783f8adSPaul Durrant !strcmp(key[i], "frontend") || 235a783f8adSPaul Durrant !strcmp(key[i], "frontend-id") || 236a783f8adSPaul Durrant !strcmp(key[i], "hotplug-status")) 237a783f8adSPaul Durrant continue; 238a783f8adSPaul Durrant 239a783f8adSPaul Durrant if (xs_node_scanf(xenbus->xsh, tid, path, key[i], NULL, "%ms", 240a783f8adSPaul Durrant &val) == 1) { 241a783f8adSPaul Durrant qdict_put_str(opts, key[i], val); 242a783f8adSPaul Durrant free(val); 243a783f8adSPaul Durrant } 244a783f8adSPaul Durrant } 245a783f8adSPaul Durrant 246a783f8adSPaul Durrant free(key); 247a783f8adSPaul Durrant 248a783f8adSPaul Durrant if (!xs_transaction_end(xenbus->xsh, tid, false)) { 249a783f8adSPaul Durrant qobject_unref(opts); 250a783f8adSPaul Durrant 251a783f8adSPaul Durrant if (errno == EAGAIN) { 252a783f8adSPaul Durrant goto again; 253a783f8adSPaul Durrant } 254a783f8adSPaul Durrant 255a783f8adSPaul Durrant error_setg_errno(errp, errno, "failed xs_transaction_end"); 256a783f8adSPaul Durrant return; 257a783f8adSPaul Durrant } 258a783f8adSPaul Durrant 259a783f8adSPaul Durrant xen_backend_device_create(xenbus, type, name, opts, &local_err); 260a783f8adSPaul Durrant qobject_unref(opts); 261a783f8adSPaul Durrant 262a783f8adSPaul Durrant if (local_err) { 263a783f8adSPaul Durrant error_propagate_prepend(errp, local_err, 264a783f8adSPaul Durrant "failed to create '%s' device '%s': ", 265a783f8adSPaul Durrant type, name); 266a783f8adSPaul Durrant } 267a783f8adSPaul Durrant } 268a783f8adSPaul Durrant 269a783f8adSPaul Durrant static void xen_bus_type_enumerate(XenBus *xenbus, const char *type) 270a783f8adSPaul Durrant { 271a783f8adSPaul Durrant char *domain_path = g_strdup_printf("backend/%s/%u", type, xen_domid); 272a783f8adSPaul Durrant char **backend; 273a783f8adSPaul Durrant unsigned int i, n; 274a783f8adSPaul Durrant 275a783f8adSPaul Durrant trace_xen_bus_type_enumerate(type); 276a783f8adSPaul Durrant 277a783f8adSPaul Durrant backend = xs_directory(xenbus->xsh, XBT_NULL, domain_path, &n); 278a783f8adSPaul Durrant if (!backend) { 279a783f8adSPaul Durrant goto out; 280a783f8adSPaul Durrant } 281a783f8adSPaul Durrant 282a783f8adSPaul Durrant for (i = 0; i < n; i++) { 283a783f8adSPaul Durrant char *backend_path = g_strdup_printf("%s/%s", domain_path, 284a783f8adSPaul Durrant backend[i]); 285a783f8adSPaul Durrant enum xenbus_state backend_state; 286a783f8adSPaul Durrant 287a783f8adSPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, backend_path, "state", 288a783f8adSPaul Durrant NULL, "%u", &backend_state) != 1) 289a783f8adSPaul Durrant backend_state = XenbusStateUnknown; 290a783f8adSPaul Durrant 291a783f8adSPaul Durrant if (backend_state == XenbusStateInitialising) { 292a783f8adSPaul Durrant Error *local_err = NULL; 293a783f8adSPaul Durrant 294a783f8adSPaul Durrant xen_bus_backend_create(xenbus, type, backend[i], backend_path, 295a783f8adSPaul Durrant &local_err); 296a783f8adSPaul Durrant if (local_err) { 297a783f8adSPaul Durrant error_report_err(local_err); 298a783f8adSPaul Durrant } 299a783f8adSPaul Durrant } 300a783f8adSPaul Durrant 301a783f8adSPaul Durrant g_free(backend_path); 302a783f8adSPaul Durrant } 303a783f8adSPaul Durrant 304a783f8adSPaul Durrant free(backend); 305a783f8adSPaul Durrant 306a783f8adSPaul Durrant out: 307a783f8adSPaul Durrant g_free(domain_path); 308a783f8adSPaul Durrant } 309a783f8adSPaul Durrant 310a783f8adSPaul Durrant static void xen_bus_enumerate(void *opaque) 311a783f8adSPaul Durrant { 312a783f8adSPaul Durrant XenBus *xenbus = opaque; 313a783f8adSPaul Durrant char **type; 314a783f8adSPaul Durrant unsigned int i, n; 315a783f8adSPaul Durrant 316a783f8adSPaul Durrant trace_xen_bus_enumerate(); 317a783f8adSPaul Durrant 318a783f8adSPaul Durrant type = xs_directory(xenbus->xsh, XBT_NULL, "backend", &n); 319a783f8adSPaul Durrant if (!type) { 320a783f8adSPaul Durrant return; 321a783f8adSPaul Durrant } 322a783f8adSPaul Durrant 323a783f8adSPaul Durrant for (i = 0; i < n; i++) { 324a783f8adSPaul Durrant xen_bus_type_enumerate(xenbus, type[i]); 325a783f8adSPaul Durrant } 326a783f8adSPaul Durrant 327a783f8adSPaul Durrant free(type); 328a783f8adSPaul Durrant } 329a783f8adSPaul Durrant 330108f7bbaSPaul Durrant static void xen_bus_unrealize(BusState *bus, Error **errp) 331108f7bbaSPaul Durrant { 332094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(bus); 333094a2239SPaul Durrant 334108f7bbaSPaul Durrant trace_xen_bus_unrealize(); 335094a2239SPaul Durrant 336a783f8adSPaul Durrant if (xenbus->backend_watch) { 337a783f8adSPaul Durrant xen_bus_remove_watch(xenbus, xenbus->backend_watch, NULL); 338a783f8adSPaul Durrant xenbus->backend_watch = NULL; 339a783f8adSPaul Durrant } 340a783f8adSPaul Durrant 341094a2239SPaul Durrant if (!xenbus->xsh) { 342094a2239SPaul Durrant return; 343094a2239SPaul Durrant } 344094a2239SPaul Durrant 34582a29e30SPaul Durrant qemu_set_fd_handler(xs_fileno(xenbus->xsh), NULL, NULL, NULL); 34682a29e30SPaul Durrant 347094a2239SPaul Durrant xs_close(xenbus->xsh); 348108f7bbaSPaul Durrant } 349108f7bbaSPaul Durrant 35082a29e30SPaul Durrant static void xen_bus_watch(void *opaque) 35182a29e30SPaul Durrant { 35282a29e30SPaul Durrant XenBus *xenbus = opaque; 35382a29e30SPaul Durrant char **v; 35482a29e30SPaul Durrant const char *token; 35582a29e30SPaul Durrant 35682a29e30SPaul Durrant g_assert(xenbus->xsh); 35782a29e30SPaul Durrant 35882a29e30SPaul Durrant v = xs_check_watch(xenbus->xsh); 35982a29e30SPaul Durrant if (!v) { 36082a29e30SPaul Durrant return; 36182a29e30SPaul Durrant } 36282a29e30SPaul Durrant 36382a29e30SPaul Durrant token = v[XS_WATCH_TOKEN]; 36482a29e30SPaul Durrant 36582a29e30SPaul Durrant trace_xen_bus_watch(token); 36682a29e30SPaul Durrant 36782a29e30SPaul Durrant notifier_list_notify(&xenbus->watch_notifiers, (void *)token); 36882a29e30SPaul Durrant 36982a29e30SPaul Durrant free(v); 37082a29e30SPaul Durrant } 37182a29e30SPaul Durrant 372108f7bbaSPaul Durrant static void xen_bus_realize(BusState *bus, Error **errp) 373108f7bbaSPaul Durrant { 374094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(bus); 375094a2239SPaul Durrant unsigned int domid; 376a783f8adSPaul Durrant Error *local_err = NULL; 377094a2239SPaul Durrant 378108f7bbaSPaul Durrant trace_xen_bus_realize(); 379094a2239SPaul Durrant 380094a2239SPaul Durrant xenbus->xsh = xs_open(0); 381094a2239SPaul Durrant if (!xenbus->xsh) { 382094a2239SPaul Durrant error_setg_errno(errp, errno, "failed xs_open"); 383094a2239SPaul Durrant goto fail; 384094a2239SPaul Durrant } 385094a2239SPaul Durrant 386094a2239SPaul Durrant if (xs_node_scanf(xenbus->xsh, XBT_NULL, "", /* domain root node */ 387094a2239SPaul Durrant "domid", NULL, "%u", &domid) == 1) { 388094a2239SPaul Durrant xenbus->backend_id = domid; 389094a2239SPaul Durrant } else { 390094a2239SPaul Durrant xenbus->backend_id = 0; /* Assume lack of node means dom0 */ 391094a2239SPaul Durrant } 392094a2239SPaul Durrant 39382a29e30SPaul Durrant notifier_list_init(&xenbus->watch_notifiers); 39482a29e30SPaul Durrant qemu_set_fd_handler(xs_fileno(xenbus->xsh), xen_bus_watch, NULL, 39582a29e30SPaul Durrant xenbus); 396a783f8adSPaul Durrant 397a783f8adSPaul Durrant module_call_init(MODULE_INIT_XEN_BACKEND); 398a783f8adSPaul Durrant 399a783f8adSPaul Durrant xenbus->backend_watch = 400a783f8adSPaul Durrant xen_bus_add_watch(xenbus, "", /* domain root node */ 401a783f8adSPaul Durrant "backend", xen_bus_enumerate, xenbus, &local_err); 402a783f8adSPaul Durrant if (local_err) { 403a783f8adSPaul Durrant /* This need not be treated as a hard error so don't propagate */ 404a783f8adSPaul Durrant error_reportf_err(local_err, 405a783f8adSPaul Durrant "failed to set up enumeration watch: "); 406a783f8adSPaul Durrant } 407a783f8adSPaul Durrant 408094a2239SPaul Durrant return; 409094a2239SPaul Durrant 410094a2239SPaul Durrant fail: 411094a2239SPaul Durrant xen_bus_unrealize(bus, &error_abort); 412108f7bbaSPaul Durrant } 413108f7bbaSPaul Durrant 414b6af8926SPaul Durrant static void xen_bus_unplug_request(HotplugHandler *hotplug, 415b6af8926SPaul Durrant DeviceState *dev, 416b6af8926SPaul Durrant Error **errp) 417b6af8926SPaul Durrant { 418b6af8926SPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 419b6af8926SPaul Durrant 420b6af8926SPaul Durrant xen_device_unplug(xendev, errp); 421b6af8926SPaul Durrant } 422b6af8926SPaul Durrant 423108f7bbaSPaul Durrant static void xen_bus_class_init(ObjectClass *class, void *data) 424108f7bbaSPaul Durrant { 425108f7bbaSPaul Durrant BusClass *bus_class = BUS_CLASS(class); 426b6af8926SPaul Durrant HotplugHandlerClass *hotplug_class = HOTPLUG_HANDLER_CLASS(class); 427108f7bbaSPaul Durrant 428094a2239SPaul Durrant bus_class->print_dev = xen_bus_print_dev; 429094a2239SPaul Durrant bus_class->get_dev_path = xen_bus_get_dev_path; 430108f7bbaSPaul Durrant bus_class->realize = xen_bus_realize; 431108f7bbaSPaul Durrant bus_class->unrealize = xen_bus_unrealize; 432b6af8926SPaul Durrant 433b6af8926SPaul Durrant hotplug_class->unplug_request = xen_bus_unplug_request; 434108f7bbaSPaul Durrant } 435108f7bbaSPaul Durrant 436108f7bbaSPaul Durrant static const TypeInfo xen_bus_type_info = { 437108f7bbaSPaul Durrant .name = TYPE_XEN_BUS, 438108f7bbaSPaul Durrant .parent = TYPE_BUS, 439108f7bbaSPaul Durrant .instance_size = sizeof(XenBus), 440108f7bbaSPaul Durrant .class_size = sizeof(XenBusClass), 441108f7bbaSPaul Durrant .class_init = xen_bus_class_init, 442108f7bbaSPaul Durrant .interfaces = (InterfaceInfo[]) { 443108f7bbaSPaul Durrant { TYPE_HOTPLUG_HANDLER }, 444108f7bbaSPaul Durrant { } 445108f7bbaSPaul Durrant }, 446108f7bbaSPaul Durrant }; 447108f7bbaSPaul Durrant 448b6af8926SPaul Durrant void xen_device_backend_printf(XenDevice *xendev, const char *key, 449094a2239SPaul Durrant const char *fmt, ...) 450094a2239SPaul Durrant { 451094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 452094a2239SPaul Durrant Error *local_err = NULL; 453094a2239SPaul Durrant va_list ap; 454094a2239SPaul Durrant 455094a2239SPaul Durrant g_assert(xenbus->xsh); 456094a2239SPaul Durrant 457094a2239SPaul Durrant va_start(ap, fmt); 458094a2239SPaul Durrant xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->backend_path, key, 459094a2239SPaul Durrant &local_err, fmt, ap); 460094a2239SPaul Durrant va_end(ap); 461094a2239SPaul Durrant 462094a2239SPaul Durrant if (local_err) { 463094a2239SPaul Durrant error_report_err(local_err); 464094a2239SPaul Durrant } 465094a2239SPaul Durrant } 466094a2239SPaul Durrant 46782a29e30SPaul Durrant static int xen_device_backend_scanf(XenDevice *xendev, const char *key, 46882a29e30SPaul Durrant const char *fmt, ...) 46982a29e30SPaul Durrant { 47082a29e30SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 47182a29e30SPaul Durrant va_list ap; 47282a29e30SPaul Durrant int rc; 47382a29e30SPaul Durrant 47482a29e30SPaul Durrant g_assert(xenbus->xsh); 47582a29e30SPaul Durrant 47682a29e30SPaul Durrant va_start(ap, fmt); 47782a29e30SPaul Durrant rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->backend_path, key, 47882a29e30SPaul Durrant NULL, fmt, ap); 47982a29e30SPaul Durrant va_end(ap); 48082a29e30SPaul Durrant 48182a29e30SPaul Durrant return rc; 48282a29e30SPaul Durrant } 48382a29e30SPaul Durrant 48482a29e30SPaul Durrant void xen_device_backend_set_state(XenDevice *xendev, 485094a2239SPaul Durrant enum xenbus_state state) 486094a2239SPaul Durrant { 487094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 488094a2239SPaul Durrant 489094a2239SPaul Durrant if (xendev->backend_state == state) { 490094a2239SPaul Durrant return; 491094a2239SPaul Durrant } 492094a2239SPaul Durrant 493094a2239SPaul Durrant trace_xen_device_backend_state(type, xendev->name, 494094a2239SPaul Durrant xs_strstate(state)); 495094a2239SPaul Durrant 496094a2239SPaul Durrant xendev->backend_state = state; 497094a2239SPaul Durrant xen_device_backend_printf(xendev, "state", "%u", state); 498094a2239SPaul Durrant } 499094a2239SPaul Durrant 50082a29e30SPaul Durrant enum xenbus_state xen_device_backend_get_state(XenDevice *xendev) 50182a29e30SPaul Durrant { 50282a29e30SPaul Durrant return xendev->backend_state; 50382a29e30SPaul Durrant } 50482a29e30SPaul Durrant 505b6af8926SPaul Durrant static void xen_device_backend_set_online(XenDevice *xendev, bool online) 506b6af8926SPaul Durrant { 507b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 508b6af8926SPaul Durrant 509b6af8926SPaul Durrant if (xendev->backend_online == online) { 510b6af8926SPaul Durrant return; 511b6af8926SPaul Durrant } 512b6af8926SPaul Durrant 513b6af8926SPaul Durrant trace_xen_device_backend_online(type, xendev->name, online); 514b6af8926SPaul Durrant 515b6af8926SPaul Durrant xendev->backend_online = online; 516b6af8926SPaul Durrant xen_device_backend_printf(xendev, "online", "%u", online); 517b6af8926SPaul Durrant } 518b6af8926SPaul Durrant 519cb323146SAnthony PERARD /* 520cb323146SAnthony PERARD * Tell from the state whether the frontend is likely alive, 521cb323146SAnthony PERARD * i.e. it will react to a change of state of the backend. 522cb323146SAnthony PERARD */ 523cb323146SAnthony PERARD static bool xen_device_state_is_active(enum xenbus_state state) 524cb323146SAnthony PERARD { 525cb323146SAnthony PERARD switch (state) { 526cb323146SAnthony PERARD case XenbusStateInitWait: 527cb323146SAnthony PERARD case XenbusStateInitialised: 528cb323146SAnthony PERARD case XenbusStateConnected: 529cb323146SAnthony PERARD case XenbusStateClosing: 530cb323146SAnthony PERARD return true; 531cb323146SAnthony PERARD default: 532cb323146SAnthony PERARD return false; 533cb323146SAnthony PERARD } 534cb323146SAnthony PERARD } 535cb323146SAnthony PERARD 536b6af8926SPaul Durrant static void xen_device_backend_changed(void *opaque) 537b6af8926SPaul Durrant { 538b6af8926SPaul Durrant XenDevice *xendev = opaque; 539b6af8926SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 540b6af8926SPaul Durrant enum xenbus_state state; 541b6af8926SPaul Durrant unsigned int online; 542b6af8926SPaul Durrant 543b6af8926SPaul Durrant trace_xen_device_backend_changed(type, xendev->name); 544b6af8926SPaul Durrant 545b6af8926SPaul Durrant if (xen_device_backend_scanf(xendev, "state", "%u", &state) != 1) { 546b6af8926SPaul Durrant state = XenbusStateUnknown; 547b6af8926SPaul Durrant } 548b6af8926SPaul Durrant 549b6af8926SPaul Durrant xen_device_backend_set_state(xendev, state); 550b6af8926SPaul Durrant 551b6af8926SPaul Durrant if (xen_device_backend_scanf(xendev, "online", "%u", &online) != 1) { 552b6af8926SPaul Durrant online = 0; 553b6af8926SPaul Durrant } 554b6af8926SPaul Durrant 555b6af8926SPaul Durrant xen_device_backend_set_online(xendev, !!online); 556b6af8926SPaul Durrant 557b6af8926SPaul Durrant /* 558b6af8926SPaul Durrant * If the toolstack (or unplug request callback) has set the backend 559cb323146SAnthony PERARD * state to Closing, but there is no active frontend then set the 560cb323146SAnthony PERARD * backend state to Closed. 561b6af8926SPaul Durrant */ 562b6af8926SPaul Durrant if (xendev->backend_state == XenbusStateClosing && 563cb323146SAnthony PERARD !xen_device_state_is_active(state)) { 564b6af8926SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateClosed); 565b6af8926SPaul Durrant } 566b6af8926SPaul Durrant 567b6af8926SPaul Durrant /* 56867bc8e00SPaul Durrant * If a backend is still 'online' then we should leave it alone but, 56967bc8e00SPaul Durrant * if a backend is not 'online', then the device should be destroyed 57067bc8e00SPaul Durrant * once the state is Closed. 571b6af8926SPaul Durrant */ 57267bc8e00SPaul Durrant if (!xendev->backend_online && 573b6af8926SPaul Durrant (xendev->backend_state == XenbusStateClosed || 574b6af8926SPaul Durrant xendev->backend_state == XenbusStateInitialising || 575b6af8926SPaul Durrant xendev->backend_state == XenbusStateInitWait || 576b6af8926SPaul Durrant xendev->backend_state == XenbusStateUnknown)) { 577a783f8adSPaul Durrant Error *local_err = NULL; 578a783f8adSPaul Durrant 579a783f8adSPaul Durrant if (!xen_backend_try_device_destroy(xendev, &local_err)) { 580b6af8926SPaul Durrant object_unparent(OBJECT(xendev)); 581b6af8926SPaul Durrant } 582a783f8adSPaul Durrant 583a783f8adSPaul Durrant if (local_err) { 584a783f8adSPaul Durrant error_report_err(local_err); 585a783f8adSPaul Durrant } 586a783f8adSPaul Durrant } 587b6af8926SPaul Durrant } 588b6af8926SPaul Durrant 589094a2239SPaul Durrant static void xen_device_backend_create(XenDevice *xendev, Error **errp) 590094a2239SPaul Durrant { 591094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 592094a2239SPaul Durrant struct xs_permissions perms[2]; 593094a2239SPaul Durrant Error *local_err = NULL; 594094a2239SPaul Durrant 595094a2239SPaul Durrant xendev->backend_path = xen_device_get_backend_path(xendev); 596094a2239SPaul Durrant 597094a2239SPaul Durrant perms[0].id = xenbus->backend_id; 598094a2239SPaul Durrant perms[0].perms = XS_PERM_NONE; 599094a2239SPaul Durrant perms[1].id = xendev->frontend_id; 600094a2239SPaul Durrant perms[1].perms = XS_PERM_READ; 601094a2239SPaul Durrant 602094a2239SPaul Durrant g_assert(xenbus->xsh); 603094a2239SPaul Durrant 604094a2239SPaul Durrant xs_node_create(xenbus->xsh, XBT_NULL, xendev->backend_path, perms, 605094a2239SPaul Durrant ARRAY_SIZE(perms), &local_err); 606094a2239SPaul Durrant if (local_err) { 607094a2239SPaul Durrant error_propagate_prepend(errp, local_err, 608094a2239SPaul Durrant "failed to create backend: "); 609b6af8926SPaul Durrant return; 610b6af8926SPaul Durrant } 611b6af8926SPaul Durrant 612b6af8926SPaul Durrant xendev->backend_state_watch = 613b6af8926SPaul Durrant xen_bus_add_watch(xenbus, xendev->backend_path, 614b6af8926SPaul Durrant "state", xen_device_backend_changed, 615b6af8926SPaul Durrant xendev, &local_err); 616b6af8926SPaul Durrant if (local_err) { 617b6af8926SPaul Durrant error_propagate_prepend(errp, local_err, 618b6af8926SPaul Durrant "failed to watch backend state: "); 619b6af8926SPaul Durrant return; 620b6af8926SPaul Durrant } 621b6af8926SPaul Durrant 622b6af8926SPaul Durrant xendev->backend_online_watch = 623b6af8926SPaul Durrant xen_bus_add_watch(xenbus, xendev->backend_path, 624b6af8926SPaul Durrant "online", xen_device_backend_changed, 625b6af8926SPaul Durrant xendev, &local_err); 626b6af8926SPaul Durrant if (local_err) { 627b6af8926SPaul Durrant error_propagate_prepend(errp, local_err, 628b6af8926SPaul Durrant "failed to watch backend online: "); 629b6af8926SPaul Durrant return; 630094a2239SPaul Durrant } 631094a2239SPaul Durrant } 632094a2239SPaul Durrant 633094a2239SPaul Durrant static void xen_device_backend_destroy(XenDevice *xendev) 634094a2239SPaul Durrant { 635094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 636094a2239SPaul Durrant Error *local_err = NULL; 637094a2239SPaul Durrant 638b6af8926SPaul Durrant if (xendev->backend_online_watch) { 639b6af8926SPaul Durrant xen_bus_remove_watch(xenbus, xendev->backend_online_watch, NULL); 640b6af8926SPaul Durrant xendev->backend_online_watch = NULL; 641b6af8926SPaul Durrant } 642b6af8926SPaul Durrant 643b6af8926SPaul Durrant if (xendev->backend_state_watch) { 644b6af8926SPaul Durrant xen_bus_remove_watch(xenbus, xendev->backend_state_watch, NULL); 645b6af8926SPaul Durrant xendev->backend_state_watch = NULL; 646b6af8926SPaul Durrant } 647b6af8926SPaul Durrant 648094a2239SPaul Durrant if (!xendev->backend_path) { 649094a2239SPaul Durrant return; 650094a2239SPaul Durrant } 651094a2239SPaul Durrant 652094a2239SPaul Durrant g_assert(xenbus->xsh); 653094a2239SPaul Durrant 654094a2239SPaul Durrant xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->backend_path, 655094a2239SPaul Durrant &local_err); 656094a2239SPaul Durrant g_free(xendev->backend_path); 657094a2239SPaul Durrant xendev->backend_path = NULL; 658094a2239SPaul Durrant 659094a2239SPaul Durrant if (local_err) { 660094a2239SPaul Durrant error_report_err(local_err); 661094a2239SPaul Durrant } 662094a2239SPaul Durrant } 663094a2239SPaul Durrant 664b6af8926SPaul Durrant void xen_device_frontend_printf(XenDevice *xendev, const char *key, 665094a2239SPaul Durrant const char *fmt, ...) 666094a2239SPaul Durrant { 667094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 668094a2239SPaul Durrant Error *local_err = NULL; 669094a2239SPaul Durrant va_list ap; 670094a2239SPaul Durrant 671094a2239SPaul Durrant g_assert(xenbus->xsh); 672094a2239SPaul Durrant 673094a2239SPaul Durrant va_start(ap, fmt); 674094a2239SPaul Durrant xs_node_vprintf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key, 675094a2239SPaul Durrant &local_err, fmt, ap); 676094a2239SPaul Durrant va_end(ap); 677094a2239SPaul Durrant 678094a2239SPaul Durrant if (local_err) { 679094a2239SPaul Durrant error_report_err(local_err); 680094a2239SPaul Durrant } 681094a2239SPaul Durrant } 682094a2239SPaul Durrant 683b6af8926SPaul Durrant int xen_device_frontend_scanf(XenDevice *xendev, const char *key, 68482a29e30SPaul Durrant const char *fmt, ...) 68582a29e30SPaul Durrant { 68682a29e30SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 68782a29e30SPaul Durrant va_list ap; 68882a29e30SPaul Durrant int rc; 68982a29e30SPaul Durrant 69082a29e30SPaul Durrant g_assert(xenbus->xsh); 69182a29e30SPaul Durrant 69282a29e30SPaul Durrant va_start(ap, fmt); 69382a29e30SPaul Durrant rc = xs_node_vscanf(xenbus->xsh, XBT_NULL, xendev->frontend_path, key, 69482a29e30SPaul Durrant NULL, fmt, ap); 69582a29e30SPaul Durrant va_end(ap); 69682a29e30SPaul Durrant 69782a29e30SPaul Durrant return rc; 69882a29e30SPaul Durrant } 69982a29e30SPaul Durrant 700094a2239SPaul Durrant static void xen_device_frontend_set_state(XenDevice *xendev, 701*705be570SAnthony PERARD enum xenbus_state state, 702*705be570SAnthony PERARD bool publish) 703094a2239SPaul Durrant { 704094a2239SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 705094a2239SPaul Durrant 706094a2239SPaul Durrant if (xendev->frontend_state == state) { 707094a2239SPaul Durrant return; 708094a2239SPaul Durrant } 709094a2239SPaul Durrant 710094a2239SPaul Durrant trace_xen_device_frontend_state(type, xendev->name, 711094a2239SPaul Durrant xs_strstate(state)); 712094a2239SPaul Durrant 713094a2239SPaul Durrant xendev->frontend_state = state; 714*705be570SAnthony PERARD if (publish) { 715094a2239SPaul Durrant xen_device_frontend_printf(xendev, "state", "%u", state); 716094a2239SPaul Durrant } 717*705be570SAnthony PERARD } 718094a2239SPaul Durrant 71982a29e30SPaul Durrant static void xen_device_frontend_changed(void *opaque) 72082a29e30SPaul Durrant { 72182a29e30SPaul Durrant XenDevice *xendev = opaque; 72282a29e30SPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 72382a29e30SPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 72482a29e30SPaul Durrant enum xenbus_state state; 72582a29e30SPaul Durrant 72682a29e30SPaul Durrant trace_xen_device_frontend_changed(type, xendev->name); 72782a29e30SPaul Durrant 72882a29e30SPaul Durrant if (xen_device_frontend_scanf(xendev, "state", "%u", &state) != 1) { 72982a29e30SPaul Durrant state = XenbusStateUnknown; 73082a29e30SPaul Durrant } 73182a29e30SPaul Durrant 732*705be570SAnthony PERARD xen_device_frontend_set_state(xendev, state, false); 73382a29e30SPaul Durrant 73467bc8e00SPaul Durrant if (state == XenbusStateInitialising && 73567bc8e00SPaul Durrant xendev->backend_state == XenbusStateClosed && 73667bc8e00SPaul Durrant xendev->backend_online) { 73767bc8e00SPaul Durrant /* 73867bc8e00SPaul Durrant * The frontend is re-initializing so switch back to 73967bc8e00SPaul Durrant * InitWait. 74067bc8e00SPaul Durrant */ 74167bc8e00SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateInitWait); 74267bc8e00SPaul Durrant return; 74367bc8e00SPaul Durrant } 74467bc8e00SPaul Durrant 74582a29e30SPaul Durrant if (xendev_class->frontend_changed) { 74682a29e30SPaul Durrant Error *local_err = NULL; 74782a29e30SPaul Durrant 74882a29e30SPaul Durrant xendev_class->frontend_changed(xendev, state, &local_err); 74982a29e30SPaul Durrant 75082a29e30SPaul Durrant if (local_err) { 75182a29e30SPaul Durrant error_reportf_err(local_err, "frontend change error: "); 75282a29e30SPaul Durrant } 75382a29e30SPaul Durrant } 75482a29e30SPaul Durrant } 75582a29e30SPaul Durrant 756094a2239SPaul Durrant static void xen_device_frontend_create(XenDevice *xendev, Error **errp) 757094a2239SPaul Durrant { 758094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 759094a2239SPaul Durrant struct xs_permissions perms[2]; 760094a2239SPaul Durrant Error *local_err = NULL; 761094a2239SPaul Durrant 762094a2239SPaul Durrant xendev->frontend_path = xen_device_get_frontend_path(xendev); 763094a2239SPaul Durrant 764094a2239SPaul Durrant perms[0].id = xendev->frontend_id; 765094a2239SPaul Durrant perms[0].perms = XS_PERM_NONE; 766094a2239SPaul Durrant perms[1].id = xenbus->backend_id; 767094a2239SPaul Durrant perms[1].perms = XS_PERM_READ | XS_PERM_WRITE; 768094a2239SPaul Durrant 769094a2239SPaul Durrant g_assert(xenbus->xsh); 770094a2239SPaul Durrant 771094a2239SPaul Durrant xs_node_create(xenbus->xsh, XBT_NULL, xendev->frontend_path, perms, 772094a2239SPaul Durrant ARRAY_SIZE(perms), &local_err); 773094a2239SPaul Durrant if (local_err) { 774094a2239SPaul Durrant error_propagate_prepend(errp, local_err, 775094a2239SPaul Durrant "failed to create frontend: "); 77682a29e30SPaul Durrant return; 77782a29e30SPaul Durrant } 77882a29e30SPaul Durrant 77982a29e30SPaul Durrant xendev->frontend_state_watch = 78082a29e30SPaul Durrant xen_bus_add_watch(xenbus, xendev->frontend_path, "state", 78182a29e30SPaul Durrant xen_device_frontend_changed, xendev, &local_err); 78282a29e30SPaul Durrant if (local_err) { 78382a29e30SPaul Durrant error_propagate_prepend(errp, local_err, 78482a29e30SPaul Durrant "failed to watch frontend state: "); 785094a2239SPaul Durrant } 786094a2239SPaul Durrant } 787094a2239SPaul Durrant 788094a2239SPaul Durrant static void xen_device_frontend_destroy(XenDevice *xendev) 789094a2239SPaul Durrant { 790094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 791094a2239SPaul Durrant Error *local_err = NULL; 792094a2239SPaul Durrant 79382a29e30SPaul Durrant if (xendev->frontend_state_watch) { 79482a29e30SPaul Durrant xen_bus_remove_watch(xenbus, xendev->frontend_state_watch, NULL); 79582a29e30SPaul Durrant xendev->frontend_state_watch = NULL; 79682a29e30SPaul Durrant } 79782a29e30SPaul Durrant 798094a2239SPaul Durrant if (!xendev->frontend_path) { 799094a2239SPaul Durrant return; 800094a2239SPaul Durrant } 801094a2239SPaul Durrant 802094a2239SPaul Durrant g_assert(xenbus->xsh); 803094a2239SPaul Durrant 804094a2239SPaul Durrant xs_node_destroy(xenbus->xsh, XBT_NULL, xendev->frontend_path, 805094a2239SPaul Durrant &local_err); 806094a2239SPaul Durrant g_free(xendev->frontend_path); 807094a2239SPaul Durrant xendev->frontend_path = NULL; 808094a2239SPaul Durrant 809094a2239SPaul Durrant if (local_err) { 810094a2239SPaul Durrant error_report_err(local_err); 811094a2239SPaul Durrant } 812094a2239SPaul Durrant } 813094a2239SPaul Durrant 8144b34b5b1SPaul Durrant void xen_device_set_max_grant_refs(XenDevice *xendev, unsigned int nr_refs, 8154b34b5b1SPaul Durrant Error **errp) 8164b34b5b1SPaul Durrant { 8174b34b5b1SPaul Durrant if (xengnttab_set_max_grants(xendev->xgth, nr_refs)) { 8184b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_set_max_grants failed"); 8194b34b5b1SPaul Durrant } 8204b34b5b1SPaul Durrant } 8214b34b5b1SPaul Durrant 8224b34b5b1SPaul Durrant void *xen_device_map_grant_refs(XenDevice *xendev, uint32_t *refs, 8234b34b5b1SPaul Durrant unsigned int nr_refs, int prot, 8244b34b5b1SPaul Durrant Error **errp) 8254b34b5b1SPaul Durrant { 8264b34b5b1SPaul Durrant void *map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_refs, 8274b34b5b1SPaul Durrant xendev->frontend_id, refs, 8284b34b5b1SPaul Durrant prot); 8294b34b5b1SPaul Durrant 8304b34b5b1SPaul Durrant if (!map) { 8314b34b5b1SPaul Durrant error_setg_errno(errp, errno, 8324b34b5b1SPaul Durrant "xengnttab_map_domain_grant_refs failed"); 8334b34b5b1SPaul Durrant } 8344b34b5b1SPaul Durrant 8354b34b5b1SPaul Durrant return map; 8364b34b5b1SPaul Durrant } 8374b34b5b1SPaul Durrant 8384b34b5b1SPaul Durrant void xen_device_unmap_grant_refs(XenDevice *xendev, void *map, 8394b34b5b1SPaul Durrant unsigned int nr_refs, Error **errp) 8404b34b5b1SPaul Durrant { 8414b34b5b1SPaul Durrant if (xengnttab_unmap(xendev->xgth, map, nr_refs)) { 8424b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_unmap failed"); 8434b34b5b1SPaul Durrant } 8444b34b5b1SPaul Durrant } 8454b34b5b1SPaul Durrant 8464b34b5b1SPaul Durrant static void compat_copy_grant_refs(XenDevice *xendev, bool to_domain, 8474b34b5b1SPaul Durrant XenDeviceGrantCopySegment segs[], 8484b34b5b1SPaul Durrant unsigned int nr_segs, Error **errp) 8494b34b5b1SPaul Durrant { 8504b34b5b1SPaul Durrant uint32_t *refs = g_new(uint32_t, nr_segs); 8514b34b5b1SPaul Durrant int prot = to_domain ? PROT_WRITE : PROT_READ; 8524b34b5b1SPaul Durrant void *map; 8534b34b5b1SPaul Durrant unsigned int i; 8544b34b5b1SPaul Durrant 8554b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 8564b34b5b1SPaul Durrant XenDeviceGrantCopySegment *seg = &segs[i]; 8574b34b5b1SPaul Durrant 8584b34b5b1SPaul Durrant refs[i] = to_domain ? seg->dest.foreign.ref : 8594b34b5b1SPaul Durrant seg->source.foreign.ref; 8604b34b5b1SPaul Durrant } 8614b34b5b1SPaul Durrant 8624b34b5b1SPaul Durrant map = xengnttab_map_domain_grant_refs(xendev->xgth, nr_segs, 8634b34b5b1SPaul Durrant xendev->frontend_id, refs, 8644b34b5b1SPaul Durrant prot); 8654b34b5b1SPaul Durrant if (!map) { 8664b34b5b1SPaul Durrant error_setg_errno(errp, errno, 8674b34b5b1SPaul Durrant "xengnttab_map_domain_grant_refs failed"); 8684b34b5b1SPaul Durrant goto done; 8694b34b5b1SPaul Durrant } 8704b34b5b1SPaul Durrant 8714b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 8724b34b5b1SPaul Durrant XenDeviceGrantCopySegment *seg = &segs[i]; 8734b34b5b1SPaul Durrant void *page = map + (i * XC_PAGE_SIZE); 8744b34b5b1SPaul Durrant 8754b34b5b1SPaul Durrant if (to_domain) { 8764b34b5b1SPaul Durrant memcpy(page + seg->dest.foreign.offset, seg->source.virt, 8774b34b5b1SPaul Durrant seg->len); 8784b34b5b1SPaul Durrant } else { 8794b34b5b1SPaul Durrant memcpy(seg->dest.virt, page + seg->source.foreign.offset, 8804b34b5b1SPaul Durrant seg->len); 8814b34b5b1SPaul Durrant } 8824b34b5b1SPaul Durrant } 8834b34b5b1SPaul Durrant 8844b34b5b1SPaul Durrant if (xengnttab_unmap(xendev->xgth, map, nr_segs)) { 8854b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_unmap failed"); 8864b34b5b1SPaul Durrant } 8874b34b5b1SPaul Durrant 8884b34b5b1SPaul Durrant done: 8894b34b5b1SPaul Durrant g_free(refs); 8904b34b5b1SPaul Durrant } 8914b34b5b1SPaul Durrant 8924b34b5b1SPaul Durrant void xen_device_copy_grant_refs(XenDevice *xendev, bool to_domain, 8934b34b5b1SPaul Durrant XenDeviceGrantCopySegment segs[], 8944b34b5b1SPaul Durrant unsigned int nr_segs, Error **errp) 8954b34b5b1SPaul Durrant { 8964b34b5b1SPaul Durrant xengnttab_grant_copy_segment_t *xengnttab_segs; 8974b34b5b1SPaul Durrant unsigned int i; 8984b34b5b1SPaul Durrant 8994b34b5b1SPaul Durrant if (!xendev->feature_grant_copy) { 9004b34b5b1SPaul Durrant compat_copy_grant_refs(xendev, to_domain, segs, nr_segs, errp); 9014b34b5b1SPaul Durrant return; 9024b34b5b1SPaul Durrant } 9034b34b5b1SPaul Durrant 9044b34b5b1SPaul Durrant xengnttab_segs = g_new0(xengnttab_grant_copy_segment_t, nr_segs); 9054b34b5b1SPaul Durrant 9064b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 9074b34b5b1SPaul Durrant XenDeviceGrantCopySegment *seg = &segs[i]; 9084b34b5b1SPaul Durrant xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; 9094b34b5b1SPaul Durrant 9104b34b5b1SPaul Durrant if (to_domain) { 9114b34b5b1SPaul Durrant xengnttab_seg->flags = GNTCOPY_dest_gref; 9124b34b5b1SPaul Durrant xengnttab_seg->dest.foreign.domid = xendev->frontend_id; 9134b34b5b1SPaul Durrant xengnttab_seg->dest.foreign.ref = seg->dest.foreign.ref; 9144b34b5b1SPaul Durrant xengnttab_seg->dest.foreign.offset = seg->dest.foreign.offset; 9154b34b5b1SPaul Durrant xengnttab_seg->source.virt = seg->source.virt; 9164b34b5b1SPaul Durrant } else { 9174b34b5b1SPaul Durrant xengnttab_seg->flags = GNTCOPY_source_gref; 9184b34b5b1SPaul Durrant xengnttab_seg->source.foreign.domid = xendev->frontend_id; 9194b34b5b1SPaul Durrant xengnttab_seg->source.foreign.ref = seg->source.foreign.ref; 9204b34b5b1SPaul Durrant xengnttab_seg->source.foreign.offset = 9214b34b5b1SPaul Durrant seg->source.foreign.offset; 9224b34b5b1SPaul Durrant xengnttab_seg->dest.virt = seg->dest.virt; 9234b34b5b1SPaul Durrant } 9244b34b5b1SPaul Durrant 9254b34b5b1SPaul Durrant xengnttab_seg->len = seg->len; 9264b34b5b1SPaul Durrant } 9274b34b5b1SPaul Durrant 9284b34b5b1SPaul Durrant if (xengnttab_grant_copy(xendev->xgth, nr_segs, xengnttab_segs)) { 9294b34b5b1SPaul Durrant error_setg_errno(errp, errno, "xengnttab_grant_copy failed"); 9304b34b5b1SPaul Durrant goto done; 9314b34b5b1SPaul Durrant } 9324b34b5b1SPaul Durrant 9334b34b5b1SPaul Durrant for (i = 0; i < nr_segs; i++) { 9344b34b5b1SPaul Durrant xengnttab_grant_copy_segment_t *xengnttab_seg = &xengnttab_segs[i]; 9354b34b5b1SPaul Durrant 9364b34b5b1SPaul Durrant if (xengnttab_seg->status != GNTST_okay) { 9374b34b5b1SPaul Durrant error_setg(errp, "xengnttab_grant_copy seg[%u] failed", i); 9384b34b5b1SPaul Durrant break; 9394b34b5b1SPaul Durrant } 9404b34b5b1SPaul Durrant } 9414b34b5b1SPaul Durrant 9424b34b5b1SPaul Durrant done: 9434b34b5b1SPaul Durrant g_free(xengnttab_segs); 9444b34b5b1SPaul Durrant } 9454b34b5b1SPaul Durrant 946a3d669c8SPaul Durrant struct XenEventChannel { 947c0b336eaSPaul Durrant QLIST_ENTRY(XenEventChannel) list; 94883361a8aSPaul Durrant AioContext *ctx; 949c0b336eaSPaul Durrant xenevtchn_handle *xeh; 950a3d669c8SPaul Durrant evtchn_port_t local_port; 951a3d669c8SPaul Durrant XenEventHandler handler; 952a3d669c8SPaul Durrant void *opaque; 953a3d669c8SPaul Durrant }; 954a3d669c8SPaul Durrant 955345f42b4SPaul Durrant static bool xen_device_poll(void *opaque) 956345f42b4SPaul Durrant { 957345f42b4SPaul Durrant XenEventChannel *channel = opaque; 958345f42b4SPaul Durrant 959345f42b4SPaul Durrant return channel->handler(channel->opaque); 960345f42b4SPaul Durrant } 961345f42b4SPaul Durrant 962c0b336eaSPaul Durrant static void xen_device_event(void *opaque) 963a3d669c8SPaul Durrant { 964c0b336eaSPaul Durrant XenEventChannel *channel = opaque; 965c0b336eaSPaul Durrant unsigned long port = xenevtchn_pending(channel->xeh); 966a3d669c8SPaul Durrant 967a3d669c8SPaul Durrant if (port == channel->local_port) { 968345f42b4SPaul Durrant xen_device_poll(channel); 969c0b336eaSPaul Durrant 970c0b336eaSPaul Durrant xenevtchn_unmask(channel->xeh, port); 971a3d669c8SPaul Durrant } 972a3d669c8SPaul Durrant } 973a3d669c8SPaul Durrant 974a3d669c8SPaul Durrant XenEventChannel *xen_device_bind_event_channel(XenDevice *xendev, 97583361a8aSPaul Durrant AioContext *ctx, 976a3d669c8SPaul Durrant unsigned int port, 977a3d669c8SPaul Durrant XenEventHandler handler, 978a3d669c8SPaul Durrant void *opaque, Error **errp) 979a3d669c8SPaul Durrant { 980a3d669c8SPaul Durrant XenEventChannel *channel = g_new0(XenEventChannel, 1); 981a3d669c8SPaul Durrant xenevtchn_port_or_error_t local_port; 982a3d669c8SPaul Durrant 983c0b336eaSPaul Durrant channel->xeh = xenevtchn_open(NULL, 0); 984c0b336eaSPaul Durrant if (!channel->xeh) { 985c0b336eaSPaul Durrant error_setg_errno(errp, errno, "failed xenevtchn_open"); 986c0b336eaSPaul Durrant goto fail; 987c0b336eaSPaul Durrant } 988c0b336eaSPaul Durrant 989c0b336eaSPaul Durrant local_port = xenevtchn_bind_interdomain(channel->xeh, 990a3d669c8SPaul Durrant xendev->frontend_id, 991a3d669c8SPaul Durrant port); 992a3d669c8SPaul Durrant if (local_port < 0) { 993a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_bind_interdomain failed"); 994c0b336eaSPaul Durrant goto fail; 995a3d669c8SPaul Durrant } 996a3d669c8SPaul Durrant 997a3d669c8SPaul Durrant channel->local_port = local_port; 998a3d669c8SPaul Durrant channel->handler = handler; 999a3d669c8SPaul Durrant channel->opaque = opaque; 1000a3d669c8SPaul Durrant 100183361a8aSPaul Durrant channel->ctx = ctx; 100283361a8aSPaul Durrant aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, 1003345f42b4SPaul Durrant xen_device_event, NULL, xen_device_poll, channel); 1004c0b336eaSPaul Durrant 1005c0b336eaSPaul Durrant QLIST_INSERT_HEAD(&xendev->event_channels, channel, list); 1006a3d669c8SPaul Durrant 1007a3d669c8SPaul Durrant return channel; 1008c0b336eaSPaul Durrant 1009c0b336eaSPaul Durrant fail: 1010c0b336eaSPaul Durrant if (channel->xeh) { 1011c0b336eaSPaul Durrant xenevtchn_close(channel->xeh); 1012c0b336eaSPaul Durrant } 1013c0b336eaSPaul Durrant 1014c0b336eaSPaul Durrant g_free(channel); 1015c0b336eaSPaul Durrant 1016c0b336eaSPaul Durrant return NULL; 1017a3d669c8SPaul Durrant } 1018a3d669c8SPaul Durrant 1019a3d669c8SPaul Durrant void xen_device_notify_event_channel(XenDevice *xendev, 1020a3d669c8SPaul Durrant XenEventChannel *channel, 1021a3d669c8SPaul Durrant Error **errp) 1022a3d669c8SPaul Durrant { 1023a3d669c8SPaul Durrant if (!channel) { 1024a3d669c8SPaul Durrant error_setg(errp, "bad channel"); 1025a3d669c8SPaul Durrant return; 1026a3d669c8SPaul Durrant } 1027a3d669c8SPaul Durrant 1028c0b336eaSPaul Durrant if (xenevtchn_notify(channel->xeh, channel->local_port) < 0) { 1029a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_notify failed"); 1030a3d669c8SPaul Durrant } 1031a3d669c8SPaul Durrant } 1032a3d669c8SPaul Durrant 1033a3d669c8SPaul Durrant void xen_device_unbind_event_channel(XenDevice *xendev, 1034a3d669c8SPaul Durrant XenEventChannel *channel, 1035a3d669c8SPaul Durrant Error **errp) 1036a3d669c8SPaul Durrant { 1037a3d669c8SPaul Durrant if (!channel) { 1038a3d669c8SPaul Durrant error_setg(errp, "bad channel"); 1039a3d669c8SPaul Durrant return; 1040a3d669c8SPaul Durrant } 1041a3d669c8SPaul Durrant 1042c0b336eaSPaul Durrant QLIST_REMOVE(channel, list); 1043a3d669c8SPaul Durrant 104483361a8aSPaul Durrant aio_set_fd_handler(channel->ctx, xenevtchn_fd(channel->xeh), true, 104583361a8aSPaul Durrant NULL, NULL, NULL, NULL); 1046c0b336eaSPaul Durrant 1047c0b336eaSPaul Durrant if (xenevtchn_unbind(channel->xeh, channel->local_port) < 0) { 1048a3d669c8SPaul Durrant error_setg_errno(errp, errno, "xenevtchn_unbind failed"); 1049a3d669c8SPaul Durrant } 1050a3d669c8SPaul Durrant 1051c0b336eaSPaul Durrant xenevtchn_close(channel->xeh); 1052a3d669c8SPaul Durrant g_free(channel); 1053a3d669c8SPaul Durrant } 1054a3d669c8SPaul Durrant 1055108f7bbaSPaul Durrant static void xen_device_unrealize(DeviceState *dev, Error **errp) 1056108f7bbaSPaul Durrant { 1057108f7bbaSPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 1058108f7bbaSPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 1059108f7bbaSPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 1060c0b336eaSPaul Durrant XenEventChannel *channel, *next; 1061108f7bbaSPaul Durrant 1062094a2239SPaul Durrant if (!xendev->name) { 1063094a2239SPaul Durrant return; 1064094a2239SPaul Durrant } 1065094a2239SPaul Durrant 1066094a2239SPaul Durrant trace_xen_device_unrealize(type, xendev->name); 1067094a2239SPaul Durrant 1068094a2239SPaul Durrant if (xendev->exit.notify) { 1069094a2239SPaul Durrant qemu_remove_exit_notifier(&xendev->exit); 1070094a2239SPaul Durrant xendev->exit.notify = NULL; 1071094a2239SPaul Durrant } 1072108f7bbaSPaul Durrant 1073108f7bbaSPaul Durrant if (xendev_class->unrealize) { 1074108f7bbaSPaul Durrant xendev_class->unrealize(xendev, errp); 1075108f7bbaSPaul Durrant } 1076094a2239SPaul Durrant 1077c0b336eaSPaul Durrant /* Make sure all event channels are cleaned up */ 1078c0b336eaSPaul Durrant QLIST_FOREACH_SAFE(channel, &xendev->event_channels, list, next) { 1079c0b336eaSPaul Durrant xen_device_unbind_event_channel(xendev, channel, NULL); 1080c0b336eaSPaul Durrant } 1081c0b336eaSPaul Durrant 1082094a2239SPaul Durrant xen_device_frontend_destroy(xendev); 1083094a2239SPaul Durrant xen_device_backend_destroy(xendev); 1084094a2239SPaul Durrant 10854b34b5b1SPaul Durrant if (xendev->xgth) { 10864b34b5b1SPaul Durrant xengnttab_close(xendev->xgth); 10874b34b5b1SPaul Durrant xendev->xgth = NULL; 10884b34b5b1SPaul Durrant } 10894b34b5b1SPaul Durrant 1090094a2239SPaul Durrant g_free(xendev->name); 1091094a2239SPaul Durrant xendev->name = NULL; 1092094a2239SPaul Durrant } 1093094a2239SPaul Durrant 1094094a2239SPaul Durrant static void xen_device_exit(Notifier *n, void *data) 1095094a2239SPaul Durrant { 1096094a2239SPaul Durrant XenDevice *xendev = container_of(n, XenDevice, exit); 1097094a2239SPaul Durrant 1098094a2239SPaul Durrant xen_device_unrealize(DEVICE(xendev), &error_abort); 1099108f7bbaSPaul Durrant } 1100108f7bbaSPaul Durrant 1101108f7bbaSPaul Durrant static void xen_device_realize(DeviceState *dev, Error **errp) 1102108f7bbaSPaul Durrant { 1103108f7bbaSPaul Durrant XenDevice *xendev = XEN_DEVICE(dev); 1104108f7bbaSPaul Durrant XenDeviceClass *xendev_class = XEN_DEVICE_GET_CLASS(xendev); 1105094a2239SPaul Durrant XenBus *xenbus = XEN_BUS(qdev_get_parent_bus(DEVICE(xendev))); 1106108f7bbaSPaul Durrant const char *type = object_get_typename(OBJECT(xendev)); 1107108f7bbaSPaul Durrant Error *local_err = NULL; 1108108f7bbaSPaul Durrant 1109094a2239SPaul Durrant if (xendev->frontend_id == DOMID_INVALID) { 1110094a2239SPaul Durrant xendev->frontend_id = xen_domid; 1111094a2239SPaul Durrant } 1112094a2239SPaul Durrant 1113094a2239SPaul Durrant if (xendev->frontend_id >= DOMID_FIRST_RESERVED) { 1114094a2239SPaul Durrant error_setg(errp, "invalid frontend-id"); 1115094a2239SPaul Durrant goto unrealize; 1116094a2239SPaul Durrant } 1117094a2239SPaul Durrant 1118094a2239SPaul Durrant if (!xendev_class->get_name) { 1119094a2239SPaul Durrant error_setg(errp, "get_name method not implemented"); 1120094a2239SPaul Durrant goto unrealize; 1121094a2239SPaul Durrant } 1122094a2239SPaul Durrant 1123094a2239SPaul Durrant xendev->name = xendev_class->get_name(xendev, &local_err); 1124094a2239SPaul Durrant if (local_err) { 1125094a2239SPaul Durrant error_propagate_prepend(errp, local_err, 1126094a2239SPaul Durrant "failed to get device name: "); 1127094a2239SPaul Durrant goto unrealize; 1128094a2239SPaul Durrant } 1129094a2239SPaul Durrant 1130094a2239SPaul Durrant trace_xen_device_realize(type, xendev->name); 1131094a2239SPaul Durrant 11324b34b5b1SPaul Durrant xendev->xgth = xengnttab_open(NULL, 0); 11334b34b5b1SPaul Durrant if (!xendev->xgth) { 11344b34b5b1SPaul Durrant error_setg_errno(errp, errno, "failed xengnttab_open"); 11354b34b5b1SPaul Durrant goto unrealize; 11364b34b5b1SPaul Durrant } 11374b34b5b1SPaul Durrant 11384b34b5b1SPaul Durrant xendev->feature_grant_copy = 11394b34b5b1SPaul Durrant (xengnttab_grant_copy(xendev->xgth, 0, NULL) == 0); 11404b34b5b1SPaul Durrant 1141094a2239SPaul Durrant xen_device_backend_create(xendev, &local_err); 1142094a2239SPaul Durrant if (local_err) { 1143094a2239SPaul Durrant error_propagate(errp, local_err); 1144094a2239SPaul Durrant goto unrealize; 1145094a2239SPaul Durrant } 1146094a2239SPaul Durrant 1147094a2239SPaul Durrant xen_device_frontend_create(xendev, &local_err); 1148094a2239SPaul Durrant if (local_err) { 1149094a2239SPaul Durrant error_propagate(errp, local_err); 1150094a2239SPaul Durrant goto unrealize; 1151094a2239SPaul Durrant } 1152108f7bbaSPaul Durrant 1153108f7bbaSPaul Durrant if (xendev_class->realize) { 1154108f7bbaSPaul Durrant xendev_class->realize(xendev, &local_err); 1155108f7bbaSPaul Durrant if (local_err) { 1156108f7bbaSPaul Durrant error_propagate(errp, local_err); 1157108f7bbaSPaul Durrant goto unrealize; 1158108f7bbaSPaul Durrant } 1159108f7bbaSPaul Durrant } 1160108f7bbaSPaul Durrant 1161094a2239SPaul Durrant xen_device_backend_printf(xendev, "frontend", "%s", 1162094a2239SPaul Durrant xendev->frontend_path); 1163094a2239SPaul Durrant xen_device_backend_printf(xendev, "frontend-id", "%u", 1164094a2239SPaul Durrant xendev->frontend_id); 1165094a2239SPaul Durrant xen_device_backend_printf(xendev, "hotplug-status", "connected"); 1166094a2239SPaul Durrant 1167b6af8926SPaul Durrant xen_device_backend_set_online(xendev, true); 1168094a2239SPaul Durrant xen_device_backend_set_state(xendev, XenbusStateInitWait); 1169094a2239SPaul Durrant 1170094a2239SPaul Durrant xen_device_frontend_printf(xendev, "backend", "%s", 1171094a2239SPaul Durrant xendev->backend_path); 1172094a2239SPaul Durrant xen_device_frontend_printf(xendev, "backend-id", "%u", 1173094a2239SPaul Durrant xenbus->backend_id); 1174094a2239SPaul Durrant 1175*705be570SAnthony PERARD xen_device_frontend_set_state(xendev, XenbusStateInitialising, true); 1176094a2239SPaul Durrant 1177094a2239SPaul Durrant xendev->exit.notify = xen_device_exit; 1178094a2239SPaul Durrant qemu_add_exit_notifier(&xendev->exit); 1179108f7bbaSPaul Durrant return; 1180108f7bbaSPaul Durrant 1181108f7bbaSPaul Durrant unrealize: 1182108f7bbaSPaul Durrant xen_device_unrealize(dev, &error_abort); 1183108f7bbaSPaul Durrant } 1184108f7bbaSPaul Durrant 1185094a2239SPaul Durrant static Property xen_device_props[] = { 1186094a2239SPaul Durrant DEFINE_PROP_UINT16("frontend-id", XenDevice, frontend_id, 1187094a2239SPaul Durrant DOMID_INVALID), 1188094a2239SPaul Durrant DEFINE_PROP_END_OF_LIST() 1189094a2239SPaul Durrant }; 1190094a2239SPaul Durrant 1191108f7bbaSPaul Durrant static void xen_device_class_init(ObjectClass *class, void *data) 1192108f7bbaSPaul Durrant { 1193108f7bbaSPaul Durrant DeviceClass *dev_class = DEVICE_CLASS(class); 1194108f7bbaSPaul Durrant 1195108f7bbaSPaul Durrant dev_class->realize = xen_device_realize; 1196108f7bbaSPaul Durrant dev_class->unrealize = xen_device_unrealize; 1197094a2239SPaul Durrant dev_class->props = xen_device_props; 1198108f7bbaSPaul Durrant dev_class->bus_type = TYPE_XEN_BUS; 1199108f7bbaSPaul Durrant } 1200108f7bbaSPaul Durrant 1201108f7bbaSPaul Durrant static const TypeInfo xen_device_type_info = { 1202108f7bbaSPaul Durrant .name = TYPE_XEN_DEVICE, 1203108f7bbaSPaul Durrant .parent = TYPE_DEVICE, 1204108f7bbaSPaul Durrant .instance_size = sizeof(XenDevice), 1205108f7bbaSPaul Durrant .abstract = true, 1206108f7bbaSPaul Durrant .class_size = sizeof(XenDeviceClass), 1207108f7bbaSPaul Durrant .class_init = xen_device_class_init, 1208108f7bbaSPaul Durrant }; 1209108f7bbaSPaul Durrant 1210108f7bbaSPaul Durrant typedef struct XenBridge { 1211108f7bbaSPaul Durrant SysBusDevice busdev; 1212108f7bbaSPaul Durrant } XenBridge; 1213108f7bbaSPaul Durrant 1214108f7bbaSPaul Durrant #define TYPE_XEN_BRIDGE "xen-bridge" 1215108f7bbaSPaul Durrant 1216108f7bbaSPaul Durrant static const TypeInfo xen_bridge_type_info = { 1217108f7bbaSPaul Durrant .name = TYPE_XEN_BRIDGE, 1218108f7bbaSPaul Durrant .parent = TYPE_SYS_BUS_DEVICE, 1219108f7bbaSPaul Durrant .instance_size = sizeof(XenBridge), 1220108f7bbaSPaul Durrant }; 1221108f7bbaSPaul Durrant 1222108f7bbaSPaul Durrant static void xen_register_types(void) 1223108f7bbaSPaul Durrant { 1224108f7bbaSPaul Durrant type_register_static(&xen_bridge_type_info); 1225108f7bbaSPaul Durrant type_register_static(&xen_bus_type_info); 1226108f7bbaSPaul Durrant type_register_static(&xen_device_type_info); 1227108f7bbaSPaul Durrant } 1228108f7bbaSPaul Durrant 1229108f7bbaSPaul Durrant type_init(xen_register_types) 1230108f7bbaSPaul Durrant 1231108f7bbaSPaul Durrant void xen_bus_init(void) 1232108f7bbaSPaul Durrant { 1233108f7bbaSPaul Durrant DeviceState *dev = qdev_create(NULL, TYPE_XEN_BRIDGE); 1234108f7bbaSPaul Durrant BusState *bus = qbus_create(TYPE_XEN_BUS, dev, NULL); 1235108f7bbaSPaul Durrant 1236108f7bbaSPaul Durrant qdev_init_nofail(dev); 1237108f7bbaSPaul Durrant qbus_set_bus_hotplug_handler(bus, &error_abort); 1238108f7bbaSPaul Durrant } 1239