1a62c8911SAndreas Färber /* 2a62c8911SAndreas Färber * Dynamic device configuration and creation -- buses. 3a62c8911SAndreas Färber * 4a62c8911SAndreas Färber * Copyright (c) 2009 CodeSourcery 5a62c8911SAndreas Färber * 6a62c8911SAndreas Färber * This library is free software; you can redistribute it and/or 7a62c8911SAndreas Färber * modify it under the terms of the GNU Lesser General Public 8a62c8911SAndreas Färber * License as published by the Free Software Foundation; either 9a62c8911SAndreas Färber * version 2 of the License, or (at your option) any later version. 10a62c8911SAndreas Färber * 11a62c8911SAndreas Färber * This library is distributed in the hope that it will be useful, 12a62c8911SAndreas Färber * but WITHOUT ANY WARRANTY; without even the implied warranty of 13a62c8911SAndreas Färber * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14a62c8911SAndreas Färber * Lesser General Public License for more details. 15a62c8911SAndreas Färber * 16a62c8911SAndreas Färber * You should have received a copy of the GNU Lesser General Public 17a62c8911SAndreas Färber * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18a62c8911SAndreas Färber */ 19a62c8911SAndreas Färber 20a62c8911SAndreas Färber #include "qemu/osdep.h" 21a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 22856dfd8aSMarkus Armbruster #include "qemu/ctype.h" 230b8fa32fSMarkus Armbruster #include "qemu/module.h" 24a62c8911SAndreas Färber #include "qapi/error.h" 25a62c8911SAndreas Färber 2694d1cc5fSMichael Roth void qbus_set_hotplug_handler(BusState *bus, Object *handler, Error **errp) 27a62c8911SAndreas Färber { 28a62c8911SAndreas Färber object_property_set_link(OBJECT(bus), OBJECT(handler), 29a62c8911SAndreas Färber QDEV_HOTPLUG_HANDLER_PROPERTY, errp); 30a62c8911SAndreas Färber } 31a62c8911SAndreas Färber 32a62c8911SAndreas Färber void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp) 33a62c8911SAndreas Färber { 3494d1cc5fSMichael Roth qbus_set_hotplug_handler(bus, OBJECT(bus), errp); 35a62c8911SAndreas Färber } 36a62c8911SAndreas Färber 37a62c8911SAndreas Färber int qbus_walk_children(BusState *bus, 38a62c8911SAndreas Färber qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, 39a62c8911SAndreas Färber qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, 40a62c8911SAndreas Färber void *opaque) 41a62c8911SAndreas Färber { 42a62c8911SAndreas Färber BusChild *kid; 43a62c8911SAndreas Färber int err; 44a62c8911SAndreas Färber 45a62c8911SAndreas Färber if (pre_busfn) { 46a62c8911SAndreas Färber err = pre_busfn(bus, opaque); 47a62c8911SAndreas Färber if (err) { 48a62c8911SAndreas Färber return err; 49a62c8911SAndreas Färber } 50a62c8911SAndreas Färber } 51a62c8911SAndreas Färber 52a62c8911SAndreas Färber QTAILQ_FOREACH(kid, &bus->children, sibling) { 53a62c8911SAndreas Färber err = qdev_walk_children(kid->child, 54a62c8911SAndreas Färber pre_devfn, pre_busfn, 55a62c8911SAndreas Färber post_devfn, post_busfn, opaque); 56a62c8911SAndreas Färber if (err < 0) { 57a62c8911SAndreas Färber return err; 58a62c8911SAndreas Färber } 59a62c8911SAndreas Färber } 60a62c8911SAndreas Färber 61a62c8911SAndreas Färber if (post_busfn) { 62a62c8911SAndreas Färber err = post_busfn(bus, opaque); 63a62c8911SAndreas Färber if (err) { 64a62c8911SAndreas Färber return err; 65a62c8911SAndreas Färber } 66a62c8911SAndreas Färber } 67a62c8911SAndreas Färber 68a62c8911SAndreas Färber return 0; 69a62c8911SAndreas Färber } 70a62c8911SAndreas Färber 71*abb89dbfSDamien Hedde void bus_cold_reset(BusState *bus) 72*abb89dbfSDamien Hedde { 73*abb89dbfSDamien Hedde resettable_reset(OBJECT(bus), RESET_TYPE_COLD); 74*abb89dbfSDamien Hedde } 75*abb89dbfSDamien Hedde 76c11256aaSDamien Hedde bool bus_is_in_reset(BusState *bus) 77c11256aaSDamien Hedde { 78c11256aaSDamien Hedde return resettable_is_in_reset(OBJECT(bus)); 79c11256aaSDamien Hedde } 80c11256aaSDamien Hedde 81c11256aaSDamien Hedde static ResettableState *bus_get_reset_state(Object *obj) 82c11256aaSDamien Hedde { 83c11256aaSDamien Hedde BusState *bus = BUS(obj); 84c11256aaSDamien Hedde return &bus->reset; 85c11256aaSDamien Hedde } 86c11256aaSDamien Hedde 87c11256aaSDamien Hedde static void bus_reset_child_foreach(Object *obj, ResettableChildCallback cb, 88c11256aaSDamien Hedde void *opaque, ResetType type) 89c11256aaSDamien Hedde { 90c11256aaSDamien Hedde BusState *bus = BUS(obj); 91c11256aaSDamien Hedde BusChild *kid; 92c11256aaSDamien Hedde 93c11256aaSDamien Hedde QTAILQ_FOREACH(kid, &bus->children, sibling) { 94c11256aaSDamien Hedde cb(OBJECT(kid->child), opaque, type); 95c11256aaSDamien Hedde } 96c11256aaSDamien Hedde } 97c11256aaSDamien Hedde 98a62c8911SAndreas Färber static void qbus_realize(BusState *bus, DeviceState *parent, const char *name) 99a62c8911SAndreas Färber { 100a62c8911SAndreas Färber const char *typename = object_get_typename(OBJECT(bus)); 101a62c8911SAndreas Färber BusClass *bc; 102f73480c3SMarc-André Lureau int i, bus_id; 103a62c8911SAndreas Färber 104a62c8911SAndreas Färber bus->parent = parent; 105a62c8911SAndreas Färber 106a62c8911SAndreas Färber if (name) { 107a62c8911SAndreas Färber bus->name = g_strdup(name); 108a62c8911SAndreas Färber } else if (bus->parent && bus->parent->id) { 109a62c8911SAndreas Färber /* parent device has id -> use it plus parent-bus-id for bus name */ 110a62c8911SAndreas Färber bus_id = bus->parent->num_child_bus; 111f73480c3SMarc-André Lureau bus->name = g_strdup_printf("%s.%d", bus->parent->id, bus_id); 112a62c8911SAndreas Färber } else { 113a62c8911SAndreas Färber /* no id -> use lowercase bus type plus global bus-id for bus name */ 114a62c8911SAndreas Färber bc = BUS_GET_CLASS(bus); 115a62c8911SAndreas Färber bus_id = bc->automatic_ids++; 116f73480c3SMarc-André Lureau bus->name = g_strdup_printf("%s.%d", typename, bus_id); 117f73480c3SMarc-André Lureau for (i = 0; bus->name[i]; i++) { 118f73480c3SMarc-André Lureau bus->name[i] = qemu_tolower(bus->name[i]); 119a62c8911SAndreas Färber } 120a62c8911SAndreas Färber } 121a62c8911SAndreas Färber 122a62c8911SAndreas Färber if (bus->parent) { 123a62c8911SAndreas Färber QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); 124a62c8911SAndreas Färber bus->parent->num_child_bus++; 125a62c8911SAndreas Färber object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL); 1260d1e8d6fSMarc-André Lureau object_unref(OBJECT(bus)); 127be1ba4d5SPeter Maydell } else { 128be1ba4d5SPeter Maydell /* The only bus without a parent is the main system bus */ 129be1ba4d5SPeter Maydell assert(bus == sysbus_get_default()); 130a62c8911SAndreas Färber } 131a62c8911SAndreas Färber } 132a62c8911SAndreas Färber 133a62c8911SAndreas Färber static void bus_unparent(Object *obj) 134a62c8911SAndreas Färber { 135a62c8911SAndreas Färber BusState *bus = BUS(obj); 136a62c8911SAndreas Färber BusChild *kid; 137a62c8911SAndreas Färber 138be1ba4d5SPeter Maydell /* Only the main system bus has no parent, and that bus is never freed */ 139be1ba4d5SPeter Maydell assert(bus->parent); 140be1ba4d5SPeter Maydell 141a62c8911SAndreas Färber while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { 142a62c8911SAndreas Färber DeviceState *dev = kid->child; 143a62c8911SAndreas Färber object_unparent(OBJECT(dev)); 144a62c8911SAndreas Färber } 145a62c8911SAndreas Färber QLIST_REMOVE(bus, sibling); 146a62c8911SAndreas Färber bus->parent->num_child_bus--; 147a62c8911SAndreas Färber bus->parent = NULL; 148a62c8911SAndreas Färber } 149a62c8911SAndreas Färber 150a62c8911SAndreas Färber void qbus_create_inplace(void *bus, size_t size, const char *typename, 151a62c8911SAndreas Färber DeviceState *parent, const char *name) 152a62c8911SAndreas Färber { 153a62c8911SAndreas Färber object_initialize(bus, size, typename); 154a62c8911SAndreas Färber qbus_realize(bus, parent, name); 155a62c8911SAndreas Färber } 156a62c8911SAndreas Färber 157a62c8911SAndreas Färber BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) 158a62c8911SAndreas Färber { 159a62c8911SAndreas Färber BusState *bus; 160a62c8911SAndreas Färber 161a62c8911SAndreas Färber bus = BUS(object_new(typename)); 162a62c8911SAndreas Färber qbus_realize(bus, parent, name); 163a62c8911SAndreas Färber 164a62c8911SAndreas Färber return bus; 165a62c8911SAndreas Färber } 166a62c8911SAndreas Färber 167a62c8911SAndreas Färber static bool bus_get_realized(Object *obj, Error **errp) 168a62c8911SAndreas Färber { 169a62c8911SAndreas Färber BusState *bus = BUS(obj); 170a62c8911SAndreas Färber 171a62c8911SAndreas Färber return bus->realized; 172a62c8911SAndreas Färber } 173a62c8911SAndreas Färber 174a62c8911SAndreas Färber static void bus_set_realized(Object *obj, bool value, Error **errp) 175a62c8911SAndreas Färber { 176a62c8911SAndreas Färber BusState *bus = BUS(obj); 177a62c8911SAndreas Färber BusClass *bc = BUS_GET_CLASS(bus); 178a62c8911SAndreas Färber BusChild *kid; 179a62c8911SAndreas Färber Error *local_err = NULL; 180a62c8911SAndreas Färber 181a62c8911SAndreas Färber if (value && !bus->realized) { 182a62c8911SAndreas Färber if (bc->realize) { 183a62c8911SAndreas Färber bc->realize(bus, &local_err); 184a62c8911SAndreas Färber } 185a62c8911SAndreas Färber 186a62c8911SAndreas Färber /* TODO: recursive realization */ 187a62c8911SAndreas Färber } else if (!value && bus->realized) { 188a62c8911SAndreas Färber QTAILQ_FOREACH(kid, &bus->children, sibling) { 189a62c8911SAndreas Färber DeviceState *dev = kid->child; 190a62c8911SAndreas Färber object_property_set_bool(OBJECT(dev), false, "realized", 191a62c8911SAndreas Färber &local_err); 192a62c8911SAndreas Färber if (local_err != NULL) { 193a62c8911SAndreas Färber break; 194a62c8911SAndreas Färber } 195a62c8911SAndreas Färber } 196a62c8911SAndreas Färber if (bc->unrealize && local_err == NULL) { 197a62c8911SAndreas Färber bc->unrealize(bus, &local_err); 198a62c8911SAndreas Färber } 199a62c8911SAndreas Färber } 200a62c8911SAndreas Färber 201a62c8911SAndreas Färber if (local_err != NULL) { 202a62c8911SAndreas Färber error_propagate(errp, local_err); 203a62c8911SAndreas Färber return; 204a62c8911SAndreas Färber } 205a62c8911SAndreas Färber 206a62c8911SAndreas Färber bus->realized = value; 207a62c8911SAndreas Färber } 208a62c8911SAndreas Färber 209a62c8911SAndreas Färber static void qbus_initfn(Object *obj) 210a62c8911SAndreas Färber { 211a62c8911SAndreas Färber BusState *bus = BUS(obj); 212a62c8911SAndreas Färber 213a62c8911SAndreas Färber QTAILQ_INIT(&bus->children); 214a62c8911SAndreas Färber object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY, 215a62c8911SAndreas Färber TYPE_HOTPLUG_HANDLER, 216a62c8911SAndreas Färber (Object **)&bus->hotplug_handler, 217a62c8911SAndreas Färber object_property_allow_set_link, 218675f22c6SMarc-André Lureau 0, 219a62c8911SAndreas Färber NULL); 220a62c8911SAndreas Färber object_property_add_bool(obj, "realized", 221a62c8911SAndreas Färber bus_get_realized, bus_set_realized, NULL); 222a62c8911SAndreas Färber } 223a62c8911SAndreas Färber 224a62c8911SAndreas Färber static char *default_bus_get_fw_dev_path(DeviceState *dev) 225a62c8911SAndreas Färber { 226a62c8911SAndreas Färber return g_strdup(object_get_typename(OBJECT(dev))); 227a62c8911SAndreas Färber } 228a62c8911SAndreas Färber 229c11256aaSDamien Hedde /** 230c11256aaSDamien Hedde * bus_phases_reset: 231c11256aaSDamien Hedde * Transition reset method for buses to allow moving 232c11256aaSDamien Hedde * smoothly from legacy reset method to multi-phases 233c11256aaSDamien Hedde */ 234c11256aaSDamien Hedde static void bus_phases_reset(BusState *bus) 235c11256aaSDamien Hedde { 236c11256aaSDamien Hedde ResettableClass *rc = RESETTABLE_GET_CLASS(bus); 237c11256aaSDamien Hedde 238c11256aaSDamien Hedde if (rc->phases.enter) { 239c11256aaSDamien Hedde rc->phases.enter(OBJECT(bus), RESET_TYPE_COLD); 240c11256aaSDamien Hedde } 241c11256aaSDamien Hedde if (rc->phases.hold) { 242c11256aaSDamien Hedde rc->phases.hold(OBJECT(bus)); 243c11256aaSDamien Hedde } 244c11256aaSDamien Hedde if (rc->phases.exit) { 245c11256aaSDamien Hedde rc->phases.exit(OBJECT(bus)); 246c11256aaSDamien Hedde } 247c11256aaSDamien Hedde } 248c11256aaSDamien Hedde 249c11256aaSDamien Hedde static void bus_transitional_reset(Object *obj) 250c11256aaSDamien Hedde { 251c11256aaSDamien Hedde BusClass *bc = BUS_GET_CLASS(obj); 252c11256aaSDamien Hedde 253c11256aaSDamien Hedde /* 254c11256aaSDamien Hedde * This will call either @bus_phases_reset (for multi-phases transitioned 255c11256aaSDamien Hedde * buses) or a bus's specific method for not-yet transitioned buses. 256c11256aaSDamien Hedde * In both case, it does not reset children. 257c11256aaSDamien Hedde */ 258c11256aaSDamien Hedde if (bc->reset) { 259c11256aaSDamien Hedde bc->reset(BUS(obj)); 260c11256aaSDamien Hedde } 261c11256aaSDamien Hedde } 262c11256aaSDamien Hedde 263c11256aaSDamien Hedde /** 264c11256aaSDamien Hedde * bus_get_transitional_reset: 265c11256aaSDamien Hedde * check if the bus's class is ready for multi-phase 266c11256aaSDamien Hedde */ 267c11256aaSDamien Hedde static ResettableTrFunction bus_get_transitional_reset(Object *obj) 268c11256aaSDamien Hedde { 269c11256aaSDamien Hedde BusClass *dc = BUS_GET_CLASS(obj); 270c11256aaSDamien Hedde if (dc->reset != bus_phases_reset) { 271c11256aaSDamien Hedde /* 272c11256aaSDamien Hedde * dc->reset has been overridden by a subclass, 273c11256aaSDamien Hedde * the bus is not ready for multi phase yet. 274c11256aaSDamien Hedde */ 275c11256aaSDamien Hedde return bus_transitional_reset; 276c11256aaSDamien Hedde } 277c11256aaSDamien Hedde return NULL; 278c11256aaSDamien Hedde } 279c11256aaSDamien Hedde 280a62c8911SAndreas Färber static void bus_class_init(ObjectClass *class, void *data) 281a62c8911SAndreas Färber { 282a62c8911SAndreas Färber BusClass *bc = BUS_CLASS(class); 283c11256aaSDamien Hedde ResettableClass *rc = RESETTABLE_CLASS(class); 284a62c8911SAndreas Färber 285a62c8911SAndreas Färber class->unparent = bus_unparent; 286a62c8911SAndreas Färber bc->get_fw_dev_path = default_bus_get_fw_dev_path; 287c11256aaSDamien Hedde 288c11256aaSDamien Hedde rc->get_state = bus_get_reset_state; 289c11256aaSDamien Hedde rc->child_foreach = bus_reset_child_foreach; 290c11256aaSDamien Hedde 291c11256aaSDamien Hedde /* 292c11256aaSDamien Hedde * @bus_phases_reset is put as the default reset method below, allowing 293c11256aaSDamien Hedde * to do the multi-phase transition from base classes to leaf classes. It 294c11256aaSDamien Hedde * allows a legacy-reset Bus class to extend a multi-phases-reset 295c11256aaSDamien Hedde * Bus class for the following reason: 296c11256aaSDamien Hedde * + If a base class B has been moved to multi-phase, then it does not 297c11256aaSDamien Hedde * override this default reset method and may have defined phase methods. 298c11256aaSDamien Hedde * + A child class C (extending class B) which uses 299c11256aaSDamien Hedde * bus_class_set_parent_reset() (or similar means) to override the 300c11256aaSDamien Hedde * reset method will still work as expected. @bus_phases_reset function 301c11256aaSDamien Hedde * will be registered as the parent reset method and effectively call 302c11256aaSDamien Hedde * parent reset phases. 303c11256aaSDamien Hedde */ 304c11256aaSDamien Hedde bc->reset = bus_phases_reset; 305c11256aaSDamien Hedde rc->get_transitional_function = bus_get_transitional_reset; 306a62c8911SAndreas Färber } 307a62c8911SAndreas Färber 308a62c8911SAndreas Färber static void qbus_finalize(Object *obj) 309a62c8911SAndreas Färber { 310a62c8911SAndreas Färber BusState *bus = BUS(obj); 311a62c8911SAndreas Färber 312f73480c3SMarc-André Lureau g_free(bus->name); 313a62c8911SAndreas Färber } 314a62c8911SAndreas Färber 315a62c8911SAndreas Färber static const TypeInfo bus_info = { 316a62c8911SAndreas Färber .name = TYPE_BUS, 317a62c8911SAndreas Färber .parent = TYPE_OBJECT, 318a62c8911SAndreas Färber .instance_size = sizeof(BusState), 319a62c8911SAndreas Färber .abstract = true, 320a62c8911SAndreas Färber .class_size = sizeof(BusClass), 321a62c8911SAndreas Färber .instance_init = qbus_initfn, 322a62c8911SAndreas Färber .instance_finalize = qbus_finalize, 323a62c8911SAndreas Färber .class_init = bus_class_init, 324c11256aaSDamien Hedde .interfaces = (InterfaceInfo[]) { 325c11256aaSDamien Hedde { TYPE_RESETTABLE_INTERFACE }, 326c11256aaSDamien Hedde { } 327c11256aaSDamien Hedde }, 328a62c8911SAndreas Färber }; 329a62c8911SAndreas Färber 330a62c8911SAndreas Färber static void bus_register_types(void) 331a62c8911SAndreas Färber { 332a62c8911SAndreas Färber type_register_static(&bus_info); 333a62c8911SAndreas Färber } 334a62c8911SAndreas Färber 335a62c8911SAndreas Färber type_init(bus_register_types) 336