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 102d637e1dcSPeter Maydell static void qbus_init_internal(BusState *bus, DeviceState *parent, 103d637e1dcSPeter 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 155d637e1dcSPeter 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); 159d637e1dcSPeter Maydell qbus_init_internal(bus, parent, name); 160a62c8911SAndreas Färber } 161a62c8911SAndreas Färber 1629388d170SPeter Maydell BusState *qbus_new(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)); 167d637e1dcSPeter 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 23512d1a768SPhilippe Mathieu-Daudé static void bus_class_init(ObjectClass *class, const void *data) 236a62c8911SAndreas Färber { 237a62c8911SAndreas Färber BusClass *bc = BUS_CLASS(class); 238c11256aaSDamien Hedde ResettableClass *rc = RESETTABLE_CLASS(class); 239a62c8911SAndreas Färber 240a62c8911SAndreas Färber class->unparent = bus_unparent; 241a62c8911SAndreas Färber bc->get_fw_dev_path = default_bus_get_fw_dev_path; 242c11256aaSDamien Hedde 243c11256aaSDamien Hedde rc->get_state = bus_get_reset_state; 244c11256aaSDamien Hedde rc->child_foreach = bus_reset_child_foreach; 245a62c8911SAndreas Färber } 246a62c8911SAndreas Färber 247a62c8911SAndreas Färber static void qbus_finalize(Object *obj) 248a62c8911SAndreas Färber { 249a62c8911SAndreas Färber BusState *bus = BUS(obj); 250a62c8911SAndreas Färber 251f73480c3SMarc-André Lureau g_free(bus->name); 252a62c8911SAndreas Färber } 253a62c8911SAndreas Färber 254a62c8911SAndreas Färber static const TypeInfo bus_info = { 255a62c8911SAndreas Färber .name = TYPE_BUS, 256a62c8911SAndreas Färber .parent = TYPE_OBJECT, 257a62c8911SAndreas Färber .instance_size = sizeof(BusState), 258a62c8911SAndreas Färber .abstract = true, 259a62c8911SAndreas Färber .class_size = sizeof(BusClass), 260a62c8911SAndreas Färber .instance_init = qbus_initfn, 261a62c8911SAndreas Färber .instance_finalize = qbus_finalize, 262a62c8911SAndreas Färber .class_init = bus_class_init, 263*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) { 264c11256aaSDamien Hedde { TYPE_RESETTABLE_INTERFACE }, 265c11256aaSDamien Hedde { } 266c11256aaSDamien Hedde }, 267a62c8911SAndreas Färber }; 268a62c8911SAndreas Färber 269a62c8911SAndreas Färber static void bus_register_types(void) 270a62c8911SAndreas Färber { 271a62c8911SAndreas Färber type_register_static(&bus_info); 272a62c8911SAndreas Färber } 273a62c8911SAndreas Färber 274a62c8911SAndreas Färber type_init(bus_register_types) 275