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 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 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 71abb89dbfSDamien Hedde void bus_cold_reset(BusState *bus) 72abb89dbfSDamien Hedde { 73abb89dbfSDamien Hedde resettable_reset(OBJECT(bus), RESET_TYPE_COLD); 74abb89dbfSDamien Hedde } 75abb89dbfSDamien 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 9830884d1bSMarkus Armbruster static void qbus_init(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++; 125d2623129SMarkus Armbruster object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus)); 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); 15430884d1bSMarkus Armbruster qbus_init(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)); 16230884d1bSMarkus Armbruster qbus_init(bus, parent, name); 163a62c8911SAndreas Färber 164a62c8911SAndreas Färber return bus; 165a62c8911SAndreas Färber } 166a62c8911SAndreas Färber 1679940b2cfSMarkus Armbruster bool qbus_realize(BusState *bus, Error **errp) 1689940b2cfSMarkus Armbruster { 169*f07ad48dSMarkus Armbruster return object_property_set_bool(OBJECT(bus), "realized", true, errp); 1709940b2cfSMarkus Armbruster } 1719940b2cfSMarkus Armbruster 1729940b2cfSMarkus Armbruster void qbus_unrealize(BusState *bus) 1739940b2cfSMarkus Armbruster { 1745325cc34SMarkus Armbruster object_property_set_bool(OBJECT(bus), "realized", false, &error_abort); 1759940b2cfSMarkus Armbruster } 1769940b2cfSMarkus Armbruster 177a62c8911SAndreas Färber static bool bus_get_realized(Object *obj, Error **errp) 178a62c8911SAndreas Färber { 179a62c8911SAndreas Färber BusState *bus = BUS(obj); 180a62c8911SAndreas Färber 181a62c8911SAndreas Färber return bus->realized; 182a62c8911SAndreas Färber } 183a62c8911SAndreas Färber 184a62c8911SAndreas Färber static void bus_set_realized(Object *obj, bool value, Error **errp) 185a62c8911SAndreas Färber { 186a62c8911SAndreas Färber BusState *bus = BUS(obj); 187a62c8911SAndreas Färber BusClass *bc = BUS_GET_CLASS(bus); 188a62c8911SAndreas Färber BusChild *kid; 189a62c8911SAndreas Färber 190a62c8911SAndreas Färber if (value && !bus->realized) { 191a62c8911SAndreas Färber if (bc->realize) { 192b69c3c21SMarkus Armbruster bc->realize(bus, errp); 193a62c8911SAndreas Färber } 194a62c8911SAndreas Färber 195a62c8911SAndreas Färber /* TODO: recursive realization */ 196a62c8911SAndreas Färber } else if (!value && bus->realized) { 197a62c8911SAndreas Färber QTAILQ_FOREACH(kid, &bus->children, sibling) { 198a62c8911SAndreas Färber DeviceState *dev = kid->child; 199981c3dcdSMarkus Armbruster qdev_unrealize(dev); 200a62c8911SAndreas Färber } 201b69c3c21SMarkus Armbruster if (bc->unrealize) { 202b69c3c21SMarkus Armbruster bc->unrealize(bus); 203a62c8911SAndreas Färber } 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, 218d2623129SMarkus Armbruster 0); 219a62c8911SAndreas Färber object_property_add_bool(obj, "realized", 220d2623129SMarkus Armbruster bus_get_realized, bus_set_realized); 221a62c8911SAndreas Färber } 222a62c8911SAndreas Färber 223a62c8911SAndreas Färber static char *default_bus_get_fw_dev_path(DeviceState *dev) 224a62c8911SAndreas Färber { 225a62c8911SAndreas Färber return g_strdup(object_get_typename(OBJECT(dev))); 226a62c8911SAndreas Färber } 227a62c8911SAndreas Färber 228c11256aaSDamien Hedde /** 229c11256aaSDamien Hedde * bus_phases_reset: 230c11256aaSDamien Hedde * Transition reset method for buses to allow moving 231c11256aaSDamien Hedde * smoothly from legacy reset method to multi-phases 232c11256aaSDamien Hedde */ 233c11256aaSDamien Hedde static void bus_phases_reset(BusState *bus) 234c11256aaSDamien Hedde { 235c11256aaSDamien Hedde ResettableClass *rc = RESETTABLE_GET_CLASS(bus); 236c11256aaSDamien Hedde 237c11256aaSDamien Hedde if (rc->phases.enter) { 238c11256aaSDamien Hedde rc->phases.enter(OBJECT(bus), RESET_TYPE_COLD); 239c11256aaSDamien Hedde } 240c11256aaSDamien Hedde if (rc->phases.hold) { 241c11256aaSDamien Hedde rc->phases.hold(OBJECT(bus)); 242c11256aaSDamien Hedde } 243c11256aaSDamien Hedde if (rc->phases.exit) { 244c11256aaSDamien Hedde rc->phases.exit(OBJECT(bus)); 245c11256aaSDamien Hedde } 246c11256aaSDamien Hedde } 247c11256aaSDamien Hedde 248c11256aaSDamien Hedde static void bus_transitional_reset(Object *obj) 249c11256aaSDamien Hedde { 250c11256aaSDamien Hedde BusClass *bc = BUS_GET_CLASS(obj); 251c11256aaSDamien Hedde 252c11256aaSDamien Hedde /* 253c11256aaSDamien Hedde * This will call either @bus_phases_reset (for multi-phases transitioned 254c11256aaSDamien Hedde * buses) or a bus's specific method for not-yet transitioned buses. 255c11256aaSDamien Hedde * In both case, it does not reset children. 256c11256aaSDamien Hedde */ 257c11256aaSDamien Hedde if (bc->reset) { 258c11256aaSDamien Hedde bc->reset(BUS(obj)); 259c11256aaSDamien Hedde } 260c11256aaSDamien Hedde } 261c11256aaSDamien Hedde 262c11256aaSDamien Hedde /** 263c11256aaSDamien Hedde * bus_get_transitional_reset: 264c11256aaSDamien Hedde * check if the bus's class is ready for multi-phase 265c11256aaSDamien Hedde */ 266c11256aaSDamien Hedde static ResettableTrFunction bus_get_transitional_reset(Object *obj) 267c11256aaSDamien Hedde { 268c11256aaSDamien Hedde BusClass *dc = BUS_GET_CLASS(obj); 269c11256aaSDamien Hedde if (dc->reset != bus_phases_reset) { 270c11256aaSDamien Hedde /* 271c11256aaSDamien Hedde * dc->reset has been overridden by a subclass, 272c11256aaSDamien Hedde * the bus is not ready for multi phase yet. 273c11256aaSDamien Hedde */ 274c11256aaSDamien Hedde return bus_transitional_reset; 275c11256aaSDamien Hedde } 276c11256aaSDamien Hedde return NULL; 277c11256aaSDamien Hedde } 278c11256aaSDamien Hedde 279a62c8911SAndreas Färber static void bus_class_init(ObjectClass *class, void *data) 280a62c8911SAndreas Färber { 281a62c8911SAndreas Färber BusClass *bc = BUS_CLASS(class); 282c11256aaSDamien Hedde ResettableClass *rc = RESETTABLE_CLASS(class); 283a62c8911SAndreas Färber 284a62c8911SAndreas Färber class->unparent = bus_unparent; 285a62c8911SAndreas Färber bc->get_fw_dev_path = default_bus_get_fw_dev_path; 286c11256aaSDamien Hedde 287c11256aaSDamien Hedde rc->get_state = bus_get_reset_state; 288c11256aaSDamien Hedde rc->child_foreach = bus_reset_child_foreach; 289c11256aaSDamien Hedde 290c11256aaSDamien Hedde /* 291c11256aaSDamien Hedde * @bus_phases_reset is put as the default reset method below, allowing 292c11256aaSDamien Hedde * to do the multi-phase transition from base classes to leaf classes. It 293c11256aaSDamien Hedde * allows a legacy-reset Bus class to extend a multi-phases-reset 294c11256aaSDamien Hedde * Bus class for the following reason: 295c11256aaSDamien Hedde * + If a base class B has been moved to multi-phase, then it does not 296c11256aaSDamien Hedde * override this default reset method and may have defined phase methods. 297c11256aaSDamien Hedde * + A child class C (extending class B) which uses 298c11256aaSDamien Hedde * bus_class_set_parent_reset() (or similar means) to override the 299c11256aaSDamien Hedde * reset method will still work as expected. @bus_phases_reset function 300c11256aaSDamien Hedde * will be registered as the parent reset method and effectively call 301c11256aaSDamien Hedde * parent reset phases. 302c11256aaSDamien Hedde */ 303c11256aaSDamien Hedde bc->reset = bus_phases_reset; 304c11256aaSDamien Hedde rc->get_transitional_function = bus_get_transitional_reset; 305a62c8911SAndreas Färber } 306a62c8911SAndreas Färber 307a62c8911SAndreas Färber static void qbus_finalize(Object *obj) 308a62c8911SAndreas Färber { 309a62c8911SAndreas Färber BusState *bus = BUS(obj); 310a62c8911SAndreas Färber 311f73480c3SMarc-André Lureau g_free(bus->name); 312a62c8911SAndreas Färber } 313a62c8911SAndreas Färber 314a62c8911SAndreas Färber static const TypeInfo bus_info = { 315a62c8911SAndreas Färber .name = TYPE_BUS, 316a62c8911SAndreas Färber .parent = TYPE_OBJECT, 317a62c8911SAndreas Färber .instance_size = sizeof(BusState), 318a62c8911SAndreas Färber .abstract = true, 319a62c8911SAndreas Färber .class_size = sizeof(BusClass), 320a62c8911SAndreas Färber .instance_init = qbus_initfn, 321a62c8911SAndreas Färber .instance_finalize = qbus_finalize, 322a62c8911SAndreas Färber .class_init = bus_class_init, 323c11256aaSDamien Hedde .interfaces = (InterfaceInfo[]) { 324c11256aaSDamien Hedde { TYPE_RESETTABLE_INTERFACE }, 325c11256aaSDamien Hedde { } 326c11256aaSDamien Hedde }, 327a62c8911SAndreas Färber }; 328a62c8911SAndreas Färber 329a62c8911SAndreas Färber static void bus_register_types(void) 330a62c8911SAndreas Färber { 331a62c8911SAndreas Färber type_register_static(&bus_info); 332a62c8911SAndreas Färber } 333a62c8911SAndreas Färber 334a62c8911SAndreas Färber type_init(bus_register_types) 335