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