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