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 961f3c91aSChetan Pant * version 2.1 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 269bc6bfdfSMarkus Armbruster void qbus_set_hotplug_handler(BusState *bus, Object *handler) 27a62c8911SAndreas Färber { 285325cc34SMarkus Armbruster object_property_set_link(OBJECT(bus), QDEV_HOTPLUG_HANDLER_PROPERTY, 295325cc34SMarkus Armbruster handler, &error_abort); 30a62c8911SAndreas Färber } 31a62c8911SAndreas Färber 32cd7c8660SMarkus Armbruster void qbus_set_bus_hotplug_handler(BusState *bus) 33a62c8911SAndreas Färber { 349bc6bfdfSMarkus Armbruster qbus_set_hotplug_handler(bus, OBJECT(bus)); 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 522d24a646SMaxim Levitsky WITH_RCU_READ_LOCK_GUARD() { 532d24a646SMaxim Levitsky QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) { 54a62c8911SAndreas Färber err = qdev_walk_children(kid->child, 55a62c8911SAndreas Färber pre_devfn, pre_busfn, 56a62c8911SAndreas Färber post_devfn, post_busfn, opaque); 57a62c8911SAndreas Färber if (err < 0) { 58a62c8911SAndreas Färber return err; 59a62c8911SAndreas Färber } 60a62c8911SAndreas Färber } 612d24a646SMaxim Levitsky } 62a62c8911SAndreas Färber 63a62c8911SAndreas Färber if (post_busfn) { 64a62c8911SAndreas Färber err = post_busfn(bus, opaque); 65a62c8911SAndreas Färber if (err) { 66a62c8911SAndreas Färber return err; 67a62c8911SAndreas Färber } 68a62c8911SAndreas Färber } 69a62c8911SAndreas Färber 70a62c8911SAndreas Färber return 0; 71a62c8911SAndreas Färber } 72a62c8911SAndreas Färber 73abb89dbfSDamien Hedde void bus_cold_reset(BusState *bus) 74abb89dbfSDamien Hedde { 75abb89dbfSDamien Hedde resettable_reset(OBJECT(bus), RESET_TYPE_COLD); 76abb89dbfSDamien Hedde } 77abb89dbfSDamien Hedde 78c11256aaSDamien Hedde bool bus_is_in_reset(BusState *bus) 79c11256aaSDamien Hedde { 80c11256aaSDamien Hedde return resettable_is_in_reset(OBJECT(bus)); 81c11256aaSDamien Hedde } 82c11256aaSDamien Hedde 83c11256aaSDamien Hedde static ResettableState *bus_get_reset_state(Object *obj) 84c11256aaSDamien Hedde { 85c11256aaSDamien Hedde BusState *bus = BUS(obj); 86c11256aaSDamien Hedde return &bus->reset; 87c11256aaSDamien Hedde } 88c11256aaSDamien Hedde 89c11256aaSDamien Hedde static void bus_reset_child_foreach(Object *obj, ResettableChildCallback cb, 90c11256aaSDamien Hedde void *opaque, ResetType type) 91c11256aaSDamien Hedde { 92c11256aaSDamien Hedde BusState *bus = BUS(obj); 93c11256aaSDamien Hedde BusChild *kid; 94c11256aaSDamien Hedde 952d24a646SMaxim Levitsky WITH_RCU_READ_LOCK_GUARD() { 962d24a646SMaxim Levitsky QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) { 97c11256aaSDamien Hedde cb(OBJECT(kid->child), opaque, type); 98c11256aaSDamien Hedde } 99c11256aaSDamien Hedde } 1002d24a646SMaxim Levitsky } 101c11256aaSDamien Hedde 102*d637e1dcSPeter Maydell static void qbus_init_internal(BusState *bus, DeviceState *parent, 103*d637e1dcSPeter Maydell const char *name) 104a62c8911SAndreas Färber { 105a62c8911SAndreas Färber const char *typename = object_get_typename(OBJECT(bus)); 106a62c8911SAndreas Färber BusClass *bc; 107f73480c3SMarc-André Lureau int i, bus_id; 108a62c8911SAndreas Färber 109a62c8911SAndreas Färber bus->parent = parent; 110a62c8911SAndreas Färber 111a62c8911SAndreas Färber if (name) { 112a62c8911SAndreas Färber bus->name = g_strdup(name); 113a62c8911SAndreas Färber } else if (bus->parent && bus->parent->id) { 114a62c8911SAndreas Färber /* parent device has id -> use it plus parent-bus-id for bus name */ 115a62c8911SAndreas Färber bus_id = bus->parent->num_child_bus; 116f73480c3SMarc-André Lureau bus->name = g_strdup_printf("%s.%d", bus->parent->id, bus_id); 117a62c8911SAndreas Färber } else { 118a62c8911SAndreas Färber /* no id -> use lowercase bus type plus global bus-id for bus name */ 119a62c8911SAndreas Färber bc = BUS_GET_CLASS(bus); 120a62c8911SAndreas Färber bus_id = bc->automatic_ids++; 121f73480c3SMarc-André Lureau bus->name = g_strdup_printf("%s.%d", typename, bus_id); 122f73480c3SMarc-André Lureau for (i = 0; bus->name[i]; i++) { 123f73480c3SMarc-André Lureau bus->name[i] = qemu_tolower(bus->name[i]); 124a62c8911SAndreas Färber } 125a62c8911SAndreas Färber } 126a62c8911SAndreas Färber 127a62c8911SAndreas Färber if (bus->parent) { 128a62c8911SAndreas Färber QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling); 129a62c8911SAndreas Färber bus->parent->num_child_bus++; 130d2623129SMarkus Armbruster object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus)); 1310d1e8d6fSMarc-André Lureau object_unref(OBJECT(bus)); 132be1ba4d5SPeter Maydell } else { 133be1ba4d5SPeter Maydell /* The only bus without a parent is the main system bus */ 134be1ba4d5SPeter Maydell assert(bus == sysbus_get_default()); 135a62c8911SAndreas Färber } 136a62c8911SAndreas Färber } 137a62c8911SAndreas Färber 138a62c8911SAndreas Färber static void bus_unparent(Object *obj) 139a62c8911SAndreas Färber { 140a62c8911SAndreas Färber BusState *bus = BUS(obj); 141a62c8911SAndreas Färber BusChild *kid; 142a62c8911SAndreas Färber 143be1ba4d5SPeter Maydell /* Only the main system bus has no parent, and that bus is never freed */ 144be1ba4d5SPeter Maydell assert(bus->parent); 145be1ba4d5SPeter Maydell 146a62c8911SAndreas Färber while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) { 147a62c8911SAndreas Färber DeviceState *dev = kid->child; 148a62c8911SAndreas Färber object_unparent(OBJECT(dev)); 149a62c8911SAndreas Färber } 150a62c8911SAndreas Färber QLIST_REMOVE(bus, sibling); 151a62c8911SAndreas Färber bus->parent->num_child_bus--; 152a62c8911SAndreas Färber bus->parent = NULL; 153a62c8911SAndreas Färber } 154a62c8911SAndreas Färber 155*d637e1dcSPeter Maydell void qbus_init(void *bus, size_t size, const char *typename, 156a62c8911SAndreas Färber DeviceState *parent, const char *name) 157a62c8911SAndreas Färber { 158a62c8911SAndreas Färber object_initialize(bus, size, typename); 159*d637e1dcSPeter Maydell qbus_init_internal(bus, parent, name); 160a62c8911SAndreas Färber } 161a62c8911SAndreas Färber 162a62c8911SAndreas Färber BusState *qbus_create(const char *typename, DeviceState *parent, const char *name) 163a62c8911SAndreas Färber { 164a62c8911SAndreas Färber BusState *bus; 165a62c8911SAndreas Färber 166a62c8911SAndreas Färber bus = BUS(object_new(typename)); 167*d637e1dcSPeter Maydell qbus_init_internal(bus, parent, name); 168a62c8911SAndreas Färber 169a62c8911SAndreas Färber return bus; 170a62c8911SAndreas Färber } 171a62c8911SAndreas Färber 1729940b2cfSMarkus Armbruster bool qbus_realize(BusState *bus, Error **errp) 1739940b2cfSMarkus Armbruster { 174f07ad48dSMarkus Armbruster return object_property_set_bool(OBJECT(bus), "realized", true, errp); 1759940b2cfSMarkus Armbruster } 1769940b2cfSMarkus Armbruster 1779940b2cfSMarkus Armbruster void qbus_unrealize(BusState *bus) 1789940b2cfSMarkus Armbruster { 1795325cc34SMarkus Armbruster object_property_set_bool(OBJECT(bus), "realized", false, &error_abort); 1809940b2cfSMarkus Armbruster } 1819940b2cfSMarkus Armbruster 182a62c8911SAndreas Färber static bool bus_get_realized(Object *obj, Error **errp) 183a62c8911SAndreas Färber { 184a62c8911SAndreas Färber BusState *bus = BUS(obj); 185a62c8911SAndreas Färber 186a62c8911SAndreas Färber return bus->realized; 187a62c8911SAndreas Färber } 188a62c8911SAndreas Färber 189a62c8911SAndreas Färber static void bus_set_realized(Object *obj, bool value, Error **errp) 190a62c8911SAndreas Färber { 191a62c8911SAndreas Färber BusState *bus = BUS(obj); 192a62c8911SAndreas Färber BusClass *bc = BUS_GET_CLASS(bus); 193a62c8911SAndreas Färber BusChild *kid; 194a62c8911SAndreas Färber 195a62c8911SAndreas Färber if (value && !bus->realized) { 196a62c8911SAndreas Färber if (bc->realize) { 197b69c3c21SMarkus Armbruster bc->realize(bus, errp); 198a62c8911SAndreas Färber } 199a62c8911SAndreas Färber 200a62c8911SAndreas Färber /* TODO: recursive realization */ 201a62c8911SAndreas Färber } else if (!value && bus->realized) { 2022d24a646SMaxim Levitsky WITH_RCU_READ_LOCK_GUARD() { 2032d24a646SMaxim Levitsky QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) { 204a62c8911SAndreas Färber DeviceState *dev = kid->child; 205981c3dcdSMarkus Armbruster qdev_unrealize(dev); 206a62c8911SAndreas Färber } 2072d24a646SMaxim Levitsky } 208b69c3c21SMarkus Armbruster if (bc->unrealize) { 209b69c3c21SMarkus Armbruster bc->unrealize(bus); 210a62c8911SAndreas Färber } 211a62c8911SAndreas Färber } 212a62c8911SAndreas Färber 213a62c8911SAndreas Färber bus->realized = value; 214a62c8911SAndreas Färber } 215a62c8911SAndreas Färber 216a62c8911SAndreas Färber static void qbus_initfn(Object *obj) 217a62c8911SAndreas Färber { 218a62c8911SAndreas Färber BusState *bus = BUS(obj); 219a62c8911SAndreas Färber 220a62c8911SAndreas Färber QTAILQ_INIT(&bus->children); 221a62c8911SAndreas Färber object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY, 222a62c8911SAndreas Färber TYPE_HOTPLUG_HANDLER, 223a62c8911SAndreas Färber (Object **)&bus->hotplug_handler, 224a62c8911SAndreas Färber object_property_allow_set_link, 225d2623129SMarkus Armbruster 0); 226a62c8911SAndreas Färber object_property_add_bool(obj, "realized", 227d2623129SMarkus Armbruster bus_get_realized, bus_set_realized); 228a62c8911SAndreas Färber } 229a62c8911SAndreas Färber 230a62c8911SAndreas Färber static char *default_bus_get_fw_dev_path(DeviceState *dev) 231a62c8911SAndreas Färber { 232a62c8911SAndreas Färber return g_strdup(object_get_typename(OBJECT(dev))); 233a62c8911SAndreas Färber } 234a62c8911SAndreas Färber 235c11256aaSDamien Hedde /** 236c11256aaSDamien Hedde * bus_phases_reset: 237c11256aaSDamien Hedde * Transition reset method for buses to allow moving 238c11256aaSDamien Hedde * smoothly from legacy reset method to multi-phases 239c11256aaSDamien Hedde */ 240c11256aaSDamien Hedde static void bus_phases_reset(BusState *bus) 241c11256aaSDamien Hedde { 242c11256aaSDamien Hedde ResettableClass *rc = RESETTABLE_GET_CLASS(bus); 243c11256aaSDamien Hedde 244c11256aaSDamien Hedde if (rc->phases.enter) { 245c11256aaSDamien Hedde rc->phases.enter(OBJECT(bus), RESET_TYPE_COLD); 246c11256aaSDamien Hedde } 247c11256aaSDamien Hedde if (rc->phases.hold) { 248c11256aaSDamien Hedde rc->phases.hold(OBJECT(bus)); 249c11256aaSDamien Hedde } 250c11256aaSDamien Hedde if (rc->phases.exit) { 251c11256aaSDamien Hedde rc->phases.exit(OBJECT(bus)); 252c11256aaSDamien Hedde } 253c11256aaSDamien Hedde } 254c11256aaSDamien Hedde 255c11256aaSDamien Hedde static void bus_transitional_reset(Object *obj) 256c11256aaSDamien Hedde { 257c11256aaSDamien Hedde BusClass *bc = BUS_GET_CLASS(obj); 258c11256aaSDamien Hedde 259c11256aaSDamien Hedde /* 260c11256aaSDamien Hedde * This will call either @bus_phases_reset (for multi-phases transitioned 261c11256aaSDamien Hedde * buses) or a bus's specific method for not-yet transitioned buses. 262c11256aaSDamien Hedde * In both case, it does not reset children. 263c11256aaSDamien Hedde */ 264c11256aaSDamien Hedde if (bc->reset) { 265c11256aaSDamien Hedde bc->reset(BUS(obj)); 266c11256aaSDamien Hedde } 267c11256aaSDamien Hedde } 268c11256aaSDamien Hedde 269c11256aaSDamien Hedde /** 270c11256aaSDamien Hedde * bus_get_transitional_reset: 271c11256aaSDamien Hedde * check if the bus's class is ready for multi-phase 272c11256aaSDamien Hedde */ 273c11256aaSDamien Hedde static ResettableTrFunction bus_get_transitional_reset(Object *obj) 274c11256aaSDamien Hedde { 275c11256aaSDamien Hedde BusClass *dc = BUS_GET_CLASS(obj); 276c11256aaSDamien Hedde if (dc->reset != bus_phases_reset) { 277c11256aaSDamien Hedde /* 278c11256aaSDamien Hedde * dc->reset has been overridden by a subclass, 279c11256aaSDamien Hedde * the bus is not ready for multi phase yet. 280c11256aaSDamien Hedde */ 281c11256aaSDamien Hedde return bus_transitional_reset; 282c11256aaSDamien Hedde } 283c11256aaSDamien Hedde return NULL; 284c11256aaSDamien Hedde } 285c11256aaSDamien Hedde 286a62c8911SAndreas Färber static void bus_class_init(ObjectClass *class, void *data) 287a62c8911SAndreas Färber { 288a62c8911SAndreas Färber BusClass *bc = BUS_CLASS(class); 289c11256aaSDamien Hedde ResettableClass *rc = RESETTABLE_CLASS(class); 290a62c8911SAndreas Färber 291a62c8911SAndreas Färber class->unparent = bus_unparent; 292a62c8911SAndreas Färber bc->get_fw_dev_path = default_bus_get_fw_dev_path; 293c11256aaSDamien Hedde 294c11256aaSDamien Hedde rc->get_state = bus_get_reset_state; 295c11256aaSDamien Hedde rc->child_foreach = bus_reset_child_foreach; 296c11256aaSDamien Hedde 297c11256aaSDamien Hedde /* 298c11256aaSDamien Hedde * @bus_phases_reset is put as the default reset method below, allowing 299c11256aaSDamien Hedde * to do the multi-phase transition from base classes to leaf classes. It 300c11256aaSDamien Hedde * allows a legacy-reset Bus class to extend a multi-phases-reset 301c11256aaSDamien Hedde * Bus class for the following reason: 302c11256aaSDamien Hedde * + If a base class B has been moved to multi-phase, then it does not 303c11256aaSDamien Hedde * override this default reset method and may have defined phase methods. 304c11256aaSDamien Hedde * + A child class C (extending class B) which uses 305c11256aaSDamien Hedde * bus_class_set_parent_reset() (or similar means) to override the 306c11256aaSDamien Hedde * reset method will still work as expected. @bus_phases_reset function 307c11256aaSDamien Hedde * will be registered as the parent reset method and effectively call 308c11256aaSDamien Hedde * parent reset phases. 309c11256aaSDamien Hedde */ 310c11256aaSDamien Hedde bc->reset = bus_phases_reset; 311c11256aaSDamien Hedde rc->get_transitional_function = bus_get_transitional_reset; 312a62c8911SAndreas Färber } 313a62c8911SAndreas Färber 314a62c8911SAndreas Färber static void qbus_finalize(Object *obj) 315a62c8911SAndreas Färber { 316a62c8911SAndreas Färber BusState *bus = BUS(obj); 317a62c8911SAndreas Färber 318f73480c3SMarc-André Lureau g_free(bus->name); 319a62c8911SAndreas Färber } 320a62c8911SAndreas Färber 321a62c8911SAndreas Färber static const TypeInfo bus_info = { 322a62c8911SAndreas Färber .name = TYPE_BUS, 323a62c8911SAndreas Färber .parent = TYPE_OBJECT, 324a62c8911SAndreas Färber .instance_size = sizeof(BusState), 325a62c8911SAndreas Färber .abstract = true, 326a62c8911SAndreas Färber .class_size = sizeof(BusClass), 327a62c8911SAndreas Färber .instance_init = qbus_initfn, 328a62c8911SAndreas Färber .instance_finalize = qbus_finalize, 329a62c8911SAndreas Färber .class_init = bus_class_init, 330c11256aaSDamien Hedde .interfaces = (InterfaceInfo[]) { 331c11256aaSDamien Hedde { TYPE_RESETTABLE_INTERFACE }, 332c11256aaSDamien Hedde { } 333c11256aaSDamien Hedde }, 334a62c8911SAndreas Färber }; 335a62c8911SAndreas Färber 336a62c8911SAndreas Färber static void bus_register_types(void) 337a62c8911SAndreas Färber { 338a62c8911SAndreas Färber type_register_static(&bus_info); 339a62c8911SAndreas Färber } 340a62c8911SAndreas Färber 341a62c8911SAndreas Färber type_init(bus_register_types) 342