]>
Commit | Line | Data |
---|---|---|
aae9460e PB |
1 | /* |
2 | * Dynamic device configuration and creation. | |
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 | |
61f3c91a | 9 | * version 2.1 of the License, or (at your option) any later version. |
aae9460e PB |
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 | |
8167ee88 | 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
aae9460e PB |
18 | */ |
19 | ||
20 | /* The theory here is that it should be possible to create a machine without | |
21 | knowledge of specific devices. Historically board init routines have | |
22 | passed a bunch of arguments to each device, requiring the board know | |
23 | exactly which device it is dealing with. This file provides an abstract | |
24 | API for device configuration and initialization. Devices will generally | |
25 | inherit from a particular bus (e.g. PCI or I2C) rather than | |
26 | this API directly. */ | |
27 | ||
18c86e2b | 28 | #include "qemu/osdep.h" |
e688df6b | 29 | #include "qapi/error.h" |
c577ff62 | 30 | #include "qapi/qapi-events-qdev.h" |
407bc4bf | 31 | #include "qobject/qdict.h" |
7b1b5d19 | 32 | #include "qapi/visitor.h" |
d49b6836 | 33 | #include "qemu/error-report.h" |
922a01a0 | 34 | #include "qemu/option.h" |
64552b6b | 35 | #include "hw/irq.h" |
a27bd6c7 | 36 | #include "hw/qdev-properties.h" |
b7454548 | 37 | #include "hw/boards.h" |
7474f1be | 38 | #include "hw/sysbus.h" |
0e6934f2 | 39 | #include "hw/qdev-clock.h" |
d6454270 | 40 | #include "migration/vmstate.h" |
70804c83 | 41 | #include "trace.h" |
aae9460e | 42 | |
0ac8ef71 | 43 | static bool qdev_hot_added = false; |
21def24a | 44 | bool qdev_hot_removed = false; |
3418bd25 | 45 | |
4be9f0d1 AL |
46 | const VMStateDescription *qdev_get_vmsd(DeviceState *dev) |
47 | { | |
6e008585 AL |
48 | DeviceClass *dc = DEVICE_GET_CLASS(dev); |
49 | return dc->vmsd; | |
4be9f0d1 AL |
50 | } |
51 | ||
2d24a646 ML |
52 | static void bus_free_bus_child(BusChild *kid) |
53 | { | |
54 | object_unref(OBJECT(kid->child)); | |
55 | g_free(kid); | |
56 | } | |
57 | ||
0866aca1 | 58 | static void bus_remove_child(BusState *bus, DeviceState *child) |
0c17542d | 59 | { |
0866aca1 AL |
60 | BusChild *kid; |
61 | ||
62 | QTAILQ_FOREACH(kid, &bus->children, sibling) { | |
63 | if (kid->child == child) { | |
64 | char name[32]; | |
65 | ||
66 | snprintf(name, sizeof(name), "child[%d]", kid->index); | |
2d24a646 | 67 | QTAILQ_REMOVE_RCU(&bus->children, kid, sibling); |
9d127820 | 68 | |
12b2e9f3 TK |
69 | bus->num_children--; |
70 | ||
9d127820 | 71 | /* This gives back ownership of kid->child back to us. */ |
df4fe0b2 | 72 | object_property_del(OBJECT(bus), name); |
2d24a646 ML |
73 | |
74 | /* free the bus kid, when it is safe to do so*/ | |
75 | call_rcu(kid, bus_free_bus_child, rcu); | |
76 | break; | |
0866aca1 AL |
77 | } |
78 | } | |
79 | } | |
80 | ||
81 | static void bus_add_child(BusState *bus, DeviceState *child) | |
82 | { | |
83 | char name[32]; | |
84 | BusChild *kid = g_malloc0(sizeof(*kid)); | |
0c17542d | 85 | |
12b2e9f3 | 86 | bus->num_children++; |
0866aca1 AL |
87 | kid->index = bus->max_index++; |
88 | kid->child = child; | |
9d127820 | 89 | object_ref(OBJECT(kid->child)); |
a5296ca9 | 90 | |
2d24a646 | 91 | QTAILQ_INSERT_HEAD_RCU(&bus->children, kid, sibling); |
0866aca1 | 92 | |
9d127820 | 93 | /* This transfers ownership of kid->child to the property. */ |
0866aca1 AL |
94 | snprintf(name, sizeof(name), "child[%d]", kid->index); |
95 | object_property_add_link(OBJECT(bus), name, | |
96 | object_get_typename(OBJECT(child)), | |
39f72ef9 SH |
97 | (Object **)&kid->child, |
98 | NULL, /* read-only property */ | |
d2623129 | 99 | 0); |
0866aca1 AL |
100 | } |
101 | ||
bb755ba4 PB |
102 | static bool bus_check_address(BusState *bus, DeviceState *child, Error **errp) |
103 | { | |
104 | BusClass *bc = BUS_GET_CLASS(bus); | |
105 | return !bc->check_address || bc->check_address(bus, child, errp); | |
106 | } | |
107 | ||
108 | bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp) | |
0866aca1 | 109 | { |
a7c3a4f9 | 110 | BusState *old_parent_bus = dev->parent_bus; |
81cb0573 MA |
111 | DeviceClass *dc = DEVICE_GET_CLASS(dev); |
112 | ||
113 | assert(dc->bus_type && object_dynamic_cast(OBJECT(bus), dc->bus_type)); | |
91c968ac | 114 | |
bb755ba4 PB |
115 | if (!bus_check_address(bus, dev, errp)) { |
116 | return false; | |
117 | } | |
118 | ||
a7c3a4f9 | 119 | if (old_parent_bus) { |
70804c83 | 120 | trace_qdev_update_parent_bus(dev, object_get_typename(OBJECT(dev)), |
a7c3a4f9 | 121 | old_parent_bus, object_get_typename(OBJECT(old_parent_bus)), |
70804c83 DH |
122 | OBJECT(bus), object_get_typename(OBJECT(bus))); |
123 | /* | |
124 | * Keep a reference to the device while it's not plugged into | |
91c968ac PM |
125 | * any bus, to avoid it potentially evaporating when it is |
126 | * dereffed in bus_remove_child(). | |
a7c3a4f9 DH |
127 | * Also keep the ref of the parent bus until the end, so that |
128 | * we can safely call resettable_change_parent() below. | |
91c968ac PM |
129 | */ |
130 | object_ref(OBJECT(dev)); | |
131 | bus_remove_child(dev->parent_bus, dev); | |
91c968ac | 132 | } |
9fbe6127 | 133 | dev->parent_bus = bus; |
62d7ba66 | 134 | object_ref(OBJECT(bus)); |
0866aca1 | 135 | bus_add_child(bus, dev); |
a7c3a4f9 DH |
136 | if (dev->realized) { |
137 | resettable_change_parent(OBJECT(dev), OBJECT(bus), | |
138 | OBJECT(old_parent_bus)); | |
139 | } | |
140 | if (old_parent_bus) { | |
141 | object_unref(OBJECT(old_parent_bus)); | |
91c968ac PM |
142 | object_unref(OBJECT(dev)); |
143 | } | |
bb755ba4 | 144 | return true; |
0c17542d MA |
145 | } |
146 | ||
9940b2cf MA |
147 | DeviceState *qdev_new(const char *name) |
148 | { | |
149 | return DEVICE(object_new(name)); | |
150 | } | |
151 | ||
9940b2cf MA |
152 | DeviceState *qdev_try_new(const char *name) |
153 | { | |
b801e3cb PB |
154 | ObjectClass *oc = module_object_class_by_name(name); |
155 | if (!oc) { | |
9940b2cf MA |
156 | return NULL; |
157 | } | |
b801e3cb | 158 | return DEVICE(object_new_with_class(oc)); |
9940b2cf MA |
159 | } |
160 | ||
eae3eb3e | 161 | static QTAILQ_HEAD(, DeviceListener) device_listeners |
707ff800 PD |
162 | = QTAILQ_HEAD_INITIALIZER(device_listeners); |
163 | ||
164 | enum ListenerDirection { Forward, Reverse }; | |
165 | ||
166 | #define DEVICE_LISTENER_CALL(_callback, _direction, _args...) \ | |
167 | do { \ | |
168 | DeviceListener *_listener; \ | |
169 | \ | |
170 | switch (_direction) { \ | |
171 | case Forward: \ | |
172 | QTAILQ_FOREACH(_listener, &device_listeners, link) { \ | |
173 | if (_listener->_callback) { \ | |
174 | _listener->_callback(_listener, ##_args); \ | |
175 | } \ | |
176 | } \ | |
177 | break; \ | |
178 | case Reverse: \ | |
179 | QTAILQ_FOREACH_REVERSE(_listener, &device_listeners, \ | |
eae3eb3e | 180 | link) { \ |
707ff800 PD |
181 | if (_listener->_callback) { \ |
182 | _listener->_callback(_listener, ##_args); \ | |
183 | } \ | |
184 | } \ | |
185 | break; \ | |
186 | default: \ | |
187 | abort(); \ | |
188 | } \ | |
189 | } while (0) | |
190 | ||
191 | static int device_listener_add(DeviceState *dev, void *opaque) | |
192 | { | |
193 | DEVICE_LISTENER_CALL(realize, Forward, dev); | |
194 | ||
195 | return 0; | |
196 | } | |
197 | ||
198 | void device_listener_register(DeviceListener *listener) | |
199 | { | |
200 | QTAILQ_INSERT_TAIL(&device_listeners, listener, link); | |
201 | ||
202 | qbus_walk_children(sysbus_get_default(), NULL, NULL, device_listener_add, | |
203 | NULL, NULL); | |
204 | } | |
205 | ||
206 | void device_listener_unregister(DeviceListener *listener) | |
207 | { | |
208 | QTAILQ_REMOVE(&device_listeners, listener, link); | |
209 | } | |
210 | ||
f3558b1b | 211 | bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp) |
f3a85056 | 212 | { |
7d618082 | 213 | ERRP_GUARD(); |
f3a85056 JF |
214 | DeviceListener *listener; |
215 | ||
216 | QTAILQ_FOREACH(listener, &device_listeners, link) { | |
b91ad981 | 217 | if (listener->hide_device) { |
f3558b1b | 218 | if (listener->hide_device(listener, opts, from_json, errp)) { |
89631fed | 219 | return true; |
7d618082 KW |
220 | } else if (*errp) { |
221 | return false; | |
89631fed | 222 | } |
f3a85056 JF |
223 | } |
224 | } | |
225 | ||
89631fed | 226 | return false; |
f3a85056 JF |
227 | } |
228 | ||
4d2ffa08 JK |
229 | void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, |
230 | int required_for_version) | |
231 | { | |
7983c8a3 | 232 | assert(!dev->realized); |
4d2ffa08 JK |
233 | dev->instance_id_alias = alias_id; |
234 | dev->alias_required_for_version = required_for_version; | |
235 | } | |
236 | ||
abb89dbf DH |
237 | void device_cold_reset(DeviceState *dev) |
238 | { | |
239 | resettable_reset(OBJECT(dev), RESET_TYPE_COLD); | |
240 | } | |
241 | ||
c11256aa DH |
242 | bool device_is_in_reset(DeviceState *dev) |
243 | { | |
244 | return resettable_is_in_reset(OBJECT(dev)); | |
245 | } | |
246 | ||
247 | static ResettableState *device_get_reset_state(Object *obj) | |
248 | { | |
249 | DeviceState *dev = DEVICE(obj); | |
250 | return &dev->reset; | |
251 | } | |
252 | ||
253 | static void device_reset_child_foreach(Object *obj, ResettableChildCallback cb, | |
254 | void *opaque, ResetType type) | |
255 | { | |
256 | DeviceState *dev = DEVICE(obj); | |
257 | BusState *bus; | |
258 | ||
259 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
260 | cb(OBJECT(bus), opaque, type); | |
261 | } | |
262 | } | |
263 | ||
9940b2cf MA |
264 | bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) |
265 | { | |
9940b2cf | 266 | assert(!dev->realized && !dev->parent_bus); |
9940b2cf | 267 | |
510ef98d | 268 | if (bus) { |
bb755ba4 PB |
269 | if (!qdev_set_parent_bus(dev, bus, errp)) { |
270 | return false; | |
271 | } | |
510ef98d MA |
272 | } else { |
273 | assert(!DEVICE_GET_CLASS(dev)->bus_type); | |
274 | } | |
9940b2cf | 275 | |
f07ad48d | 276 | return object_property_set_bool(OBJECT(dev), "realized", true, errp); |
9940b2cf MA |
277 | } |
278 | ||
9940b2cf MA |
279 | bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp) |
280 | { | |
281 | bool ret; | |
282 | ||
283 | ret = qdev_realize(dev, bus, errp); | |
284 | object_unref(OBJECT(dev)); | |
285 | return ret; | |
286 | } | |
287 | ||
288 | void qdev_unrealize(DeviceState *dev) | |
289 | { | |
5325cc34 | 290 | object_property_set_bool(OBJECT(dev), "realized", false, &error_abort); |
9940b2cf MA |
291 | } |
292 | ||
f66dc873 | 293 | static int qdev_assert_realized_properly_cb(Object *obj, void *opaque) |
dfe8c79c MA |
294 | { |
295 | DeviceState *dev = DEVICE(object_dynamic_cast(obj, TYPE_DEVICE)); | |
296 | DeviceClass *dc; | |
297 | ||
298 | if (dev) { | |
299 | dc = DEVICE_GET_CLASS(dev); | |
300 | assert(dev->realized); | |
301 | assert(dev->parent_bus || !dc->bus_type); | |
302 | } | |
303 | return 0; | |
304 | } | |
305 | ||
f66dc873 | 306 | void qdev_assert_realized_properly(void) |
3418bd25 | 307 | { |
dfe8c79c | 308 | object_child_foreach_recursive(object_get_root(), |
f66dc873 | 309 | qdev_assert_realized_properly_cb, NULL); |
3418bd25 GH |
310 | } |
311 | ||
0ac8ef71 AW |
312 | bool qdev_machine_modified(void) |
313 | { | |
314 | return qdev_hot_added || qdev_hot_removed; | |
315 | } | |
316 | ||
2d2f2507 | 317 | BusState *qdev_get_parent_bus(const DeviceState *dev) |
aae9460e | 318 | { |
02e2da45 | 319 | return dev->parent_bus; |
aae9460e PB |
320 | } |
321 | ||
02e2da45 | 322 | BusState *qdev_get_child_bus(DeviceState *dev, const char *name) |
4d6ae674 | 323 | { |
02e2da45 | 324 | BusState *bus; |
f698c8ba PC |
325 | Object *child = object_resolve_path_component(OBJECT(dev), name); |
326 | ||
327 | bus = (BusState *)object_dynamic_cast(child, TYPE_BUS); | |
328 | if (bus) { | |
329 | return bus; | |
330 | } | |
4d6ae674 | 331 | |
72cf2d4f | 332 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { |
4d6ae674 | 333 | if (strcmp(name, bus->name) == 0) { |
02e2da45 | 334 | return bus; |
4d6ae674 PB |
335 | } |
336 | } | |
337 | return NULL; | |
338 | } | |
339 | ||
0293214b PB |
340 | int qdev_walk_children(DeviceState *dev, |
341 | qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, | |
342 | qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, | |
343 | void *opaque) | |
81699d8a AL |
344 | { |
345 | BusState *bus; | |
346 | int err; | |
347 | ||
0293214b PB |
348 | if (pre_devfn) { |
349 | err = pre_devfn(dev, opaque); | |
81699d8a AL |
350 | if (err) { |
351 | return err; | |
352 | } | |
353 | } | |
354 | ||
355 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
0293214b PB |
356 | err = qbus_walk_children(bus, pre_devfn, pre_busfn, |
357 | post_devfn, post_busfn, opaque); | |
81699d8a AL |
358 | if (err < 0) { |
359 | return err; | |
360 | } | |
361 | } | |
362 | ||
0293214b PB |
363 | if (post_devfn) { |
364 | err = post_devfn(dev, opaque); | |
365 | if (err) { | |
366 | return err; | |
367 | } | |
368 | } | |
369 | ||
81699d8a AL |
370 | return 0; |
371 | } | |
372 | ||
a2ee6b4f | 373 | DeviceState *qdev_find_recursive(BusState *bus, const char *id) |
3418bd25 | 374 | { |
0866aca1 AL |
375 | BusChild *kid; |
376 | DeviceState *ret; | |
3418bd25 GH |
377 | BusState *child; |
378 | ||
2d24a646 ML |
379 | WITH_RCU_READ_LOCK_GUARD() { |
380 | QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) { | |
381 | DeviceState *dev = kid->child; | |
0866aca1 | 382 | |
2d24a646 ML |
383 | if (dev->id && strcmp(dev->id, id) == 0) { |
384 | return dev; | |
385 | } | |
0866aca1 | 386 | |
2d24a646 ML |
387 | QLIST_FOREACH(child, &dev->child_bus, sibling) { |
388 | ret = qdev_find_recursive(child, id); | |
389 | if (ret) { | |
390 | return ret; | |
391 | } | |
3418bd25 GH |
392 | } |
393 | } | |
394 | } | |
395 | return NULL; | |
396 | } | |
397 | ||
09e5ab63 | 398 | char *qdev_get_dev_path(DeviceState *dev) |
85ed303b | 399 | { |
0d936928 | 400 | BusClass *bc; |
09e5ab63 AL |
401 | |
402 | if (!dev || !dev->parent_bus) { | |
403 | return NULL; | |
404 | } | |
405 | ||
0d936928 AL |
406 | bc = BUS_GET_CLASS(dev->parent_bus); |
407 | if (bc->get_dev_path) { | |
408 | return bc->get_dev_path(dev); | |
09e5ab63 AL |
409 | } |
410 | ||
411 | return NULL; | |
44677ded | 412 | } |
a5296ca9 | 413 | |
217c7f01 JR |
414 | void qdev_add_unplug_blocker(DeviceState *dev, Error *reason) |
415 | { | |
416 | dev->unplug_blockers = g_slist_prepend(dev->unplug_blockers, reason); | |
417 | } | |
418 | ||
419 | void qdev_del_unplug_blocker(DeviceState *dev, Error *reason) | |
420 | { | |
421 | dev->unplug_blockers = g_slist_remove(dev->unplug_blockers, reason); | |
422 | } | |
423 | ||
424 | bool qdev_unplug_blocked(DeviceState *dev, Error **errp) | |
425 | { | |
217c7f01 JR |
426 | if (dev->unplug_blockers) { |
427 | error_propagate(errp, error_copy(dev->unplug_blockers->data)); | |
428 | return true; | |
429 | } | |
430 | ||
431 | return false; | |
432 | } | |
433 | ||
a7737e44 | 434 | static bool device_get_realized(Object *obj, Error **errp) |
249d4172 AF |
435 | { |
436 | DeviceState *dev = DEVICE(obj); | |
437 | return dev->realized; | |
438 | } | |
439 | ||
40f03bd5 | 440 | static bool check_only_migratable(Object *obj, Error **errp) |
1bfe5f05 JQ |
441 | { |
442 | DeviceClass *dc = DEVICE_GET_CLASS(obj); | |
443 | ||
444 | if (!vmstate_check_only_migratable(dc->vmsd)) { | |
40f03bd5 | 445 | error_setg(errp, "Device %s is not migratable, but " |
1bfe5f05 JQ |
446 | "--only-migratable was specified", |
447 | object_get_typename(obj)); | |
448 | return false; | |
449 | } | |
450 | ||
451 | return true; | |
452 | } | |
453 | ||
a7737e44 | 454 | static void device_set_realized(Object *obj, bool value, Error **errp) |
249d4172 AF |
455 | { |
456 | DeviceState *dev = DEVICE(obj); | |
457 | DeviceClass *dc = DEVICE_GET_CLASS(dev); | |
7716b8ca | 458 | HotplugHandler *hotplug_ctrl; |
5c21ce77 | 459 | BusState *bus; |
0e6934f2 | 460 | NamedClockList *ncl; |
249d4172 | 461 | Error *local_err = NULL; |
69382d8b IM |
462 | bool unattached_parent = false; |
463 | static int unattached_count; | |
249d4172 | 464 | |
1a37eca1 | 465 | if (dev->hotplugged && !dc->hotpluggable) { |
f95b25c3 PMD |
466 | error_setg(errp, "Device '%s' does not support hotplugging", |
467 | object_get_typename(obj)); | |
1a37eca1 IM |
468 | return; |
469 | } | |
470 | ||
249d4172 | 471 | if (value && !dev->realized) { |
a5f9b9df | 472 | if (!check_only_migratable(obj, errp)) { |
7562f907 AA |
473 | goto fail; |
474 | } | |
475 | ||
d578029e | 476 | if (!obj->parent) { |
249d4172 AF |
477 | gchar *name = g_strdup_printf("device[%d]", unattached_count++); |
478 | ||
1c343358 | 479 | object_property_add_child(machine_get_container("unattached"), |
d2623129 | 480 | name, obj); |
69382d8b | 481 | unattached_parent = true; |
249d4172 AF |
482 | g_free(name); |
483 | } | |
484 | ||
41346263 IM |
485 | hotplug_ctrl = qdev_get_hotplug_handler(dev); |
486 | if (hotplug_ctrl) { | |
487 | hotplug_handler_pre_plug(hotplug_ctrl, dev, &local_err); | |
488 | if (local_err != NULL) { | |
489 | goto fail; | |
490 | } | |
491 | } | |
492 | ||
a7ddba52 IM |
493 | if (dc->realize) { |
494 | dc->realize(dev, &local_err); | |
40f03bd5 VSO |
495 | if (local_err != NULL) { |
496 | goto fail; | |
497 | } | |
1d45a705 GA |
498 | } |
499 | ||
707ff800 PD |
500 | DEVICE_LISTENER_CALL(realize, Forward, dev); |
501 | ||
04162f8f MR |
502 | /* |
503 | * always free/re-initialize here since the value cannot be cleaned up | |
504 | * in device_unrealize due to its usage later on in the unplug path | |
505 | */ | |
506 | g_free(dev->canonical_path); | |
507 | dev->canonical_path = object_get_canonical_path(OBJECT(dev)); | |
0e6934f2 DH |
508 | QLIST_FOREACH(ncl, &dev->clocks, node) { |
509 | if (ncl->alias) { | |
510 | continue; | |
511 | } else { | |
512 | clock_setup_canonical_path(ncl->clock); | |
513 | } | |
514 | } | |
04162f8f | 515 | |
1d45a705 | 516 | if (qdev_get_vmsd(dev)) { |
3cad405b | 517 | if (vmstate_register_with_alias_id(VMSTATE_IF(dev), |
1df2c9a2 PX |
518 | VMSTATE_INSTANCE_ID_ANY, |
519 | qdev_get_vmsd(dev), dev, | |
67980031 DDAG |
520 | dev->instance_id_alias, |
521 | dev->alias_required_for_version, | |
522 | &local_err) < 0) { | |
523 | goto post_realize_fail; | |
524 | } | |
249d4172 | 525 | } |
1d45a705 | 526 | |
e755e127 DH |
527 | /* |
528 | * Clear the reset state, in case the object was previously unrealized | |
529 | * with a dirty state. | |
530 | */ | |
531 | resettable_state_clear(&dev->reset); | |
532 | ||
1d45a705 | 533 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { |
f1483b46 | 534 | if (!qbus_realize(bus, errp)) { |
1d45a705 | 535 | goto child_realize_fail; |
5c21ce77 BD |
536 | } |
537 | } | |
1d45a705 | 538 | if (dev->hotplugged) { |
e755e127 DH |
539 | /* |
540 | * Reset the device, as well as its subtree which, at this point, | |
541 | * should be realized too. | |
542 | */ | |
543 | resettable_assert_reset(OBJECT(dev), RESET_TYPE_COLD); | |
544 | resettable_change_parent(OBJECT(dev), OBJECT(dev->parent_bus), | |
545 | NULL); | |
546 | resettable_release_reset(OBJECT(dev), RESET_TYPE_COLD); | |
249d4172 | 547 | } |
352e8da7 | 548 | dev->pending_deleted_event = false; |
25e89788 SH |
549 | |
550 | if (hotplug_ctrl) { | |
8b5e6caf IM |
551 | hotplug_handler_plug(hotplug_ctrl, dev, &local_err); |
552 | if (local_err != NULL) { | |
553 | goto child_realize_fail; | |
554 | } | |
555 | } | |
556 | ||
a23151e8 ML |
557 | qatomic_store_release(&dev->realized, value); |
558 | ||
249d4172 | 559 | } else if (!value && dev->realized) { |
a23151e8 ML |
560 | |
561 | /* | |
562 | * Change the value so that any concurrent users are aware | |
563 | * that the device is going to be unrealized | |
564 | * | |
565 | * TODO: change .realized property to enum that states | |
566 | * each phase of the device realization/unrealization | |
567 | */ | |
568 | ||
569 | qatomic_set(&dev->realized, value); | |
570 | /* | |
571 | * Ensure that concurrent users see this update prior to | |
572 | * any other changes done by unrealize. | |
573 | */ | |
574 | smp_wmb(); | |
575 | ||
5c21ce77 | 576 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { |
f1483b46 | 577 | qbus_unrealize(bus); |
5c21ce77 | 578 | } |
cd4520ad | 579 | if (qdev_get_vmsd(dev)) { |
3cad405b | 580 | vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); |
fe6c2117 | 581 | } |
cd4520ad | 582 | if (dc->unrealize) { |
b69c3c21 | 583 | dc->unrealize(dev); |
249d4172 | 584 | } |
352e8da7 | 585 | dev->pending_deleted_event = true; |
707ff800 | 586 | DEVICE_LISTENER_CALL(unrealize, Reverse, dev); |
249d4172 AF |
587 | } |
588 | ||
40f03bd5 | 589 | assert(local_err == NULL); |
1d45a705 GA |
590 | return; |
591 | ||
592 | child_realize_fail: | |
593 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
f1483b46 | 594 | qbus_unrealize(bus); |
1d45a705 GA |
595 | } |
596 | ||
597 | if (qdev_get_vmsd(dev)) { | |
3cad405b | 598 | vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); |
1d45a705 GA |
599 | } |
600 | ||
601 | post_realize_fail: | |
04162f8f MR |
602 | g_free(dev->canonical_path); |
603 | dev->canonical_path = NULL; | |
1d45a705 | 604 | if (dc->unrealize) { |
b69c3c21 | 605 | dc->unrealize(dev); |
1d45a705 GA |
606 | } |
607 | ||
608 | fail: | |
609 | error_propagate(errp, local_err); | |
69382d8b | 610 | if (unattached_parent) { |
9940b2cf MA |
611 | /* |
612 | * Beware, this doesn't just revert | |
613 | * object_property_add_child(), it also runs bus_remove()! | |
614 | */ | |
69382d8b IM |
615 | object_unparent(OBJECT(dev)); |
616 | unattached_count--; | |
617 | } | |
249d4172 AF |
618 | } |
619 | ||
a7737e44 | 620 | static bool device_get_hotpluggable(Object *obj, Error **errp) |
1a37eca1 IM |
621 | { |
622 | DeviceClass *dc = DEVICE_GET_CLASS(obj); | |
623 | DeviceState *dev = DEVICE(obj); | |
624 | ||
2b81b35f | 625 | return dc->hotpluggable && (dev->parent_bus == NULL || |
39b888bd | 626 | qbus_is_hotpluggable(dev->parent_bus)); |
1a37eca1 IM |
627 | } |
628 | ||
40f03bd5 | 629 | static bool device_get_hotplugged(Object *obj, Error **errp) |
d012ffc1 IM |
630 | { |
631 | DeviceState *dev = DEVICE(obj); | |
632 | ||
633 | return dev->hotplugged; | |
634 | } | |
635 | ||
9674bfe4 AL |
636 | static void device_initfn(Object *obj) |
637 | { | |
638 | DeviceState *dev = DEVICE(obj); | |
9674bfe4 | 639 | |
2f181fbd | 640 | if (phase_check(PHASE_MACHINE_READY)) { |
9674bfe4 AL |
641 | dev->hotplugged = 1; |
642 | qdev_hot_added = true; | |
643 | } | |
644 | ||
645 | dev->instance_id_alias = -1; | |
7983c8a3 | 646 | dev->realized = false; |
a1190ab6 | 647 | dev->allow_unplug_during_migration = false; |
9674bfe4 | 648 | |
a5f54290 | 649 | QLIST_INIT(&dev->gpios); |
0e6934f2 | 650 | QLIST_INIT(&dev->clocks); |
9674bfe4 AL |
651 | } |
652 | ||
1c3994f6 MAL |
653 | static void device_post_init(Object *obj) |
654 | { | |
1a3ec8c1 MA |
655 | /* |
656 | * Note: ordered so that the user's global properties take | |
657 | * precedence. | |
658 | */ | |
1c3994f6 | 659 | object_apply_compat_props(obj); |
25f8dd96 | 660 | qdev_prop_set_globals(DEVICE(obj)); |
99a0b036 EH |
661 | } |
662 | ||
60adba37 AL |
663 | /* Unlink device from bus and free the structure. */ |
664 | static void device_finalize(Object *obj) | |
665 | { | |
a5f54290 PC |
666 | NamedGPIOList *ngl, *next; |
667 | ||
60adba37 | 668 | DeviceState *dev = DEVICE(obj); |
a5f54290 | 669 | |
217c7f01 JR |
670 | g_assert(!dev->unplug_blockers); |
671 | ||
a5f54290 PC |
672 | QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) { |
673 | QLIST_REMOVE(ngl, node); | |
f173d57a | 674 | qemu_free_irqs(ngl->in, ngl->num_in); |
a5f54290 PC |
675 | g_free(ngl->name); |
676 | g_free(ngl); | |
677 | /* ngl->out irqs are owned by the other end and should not be freed | |
678 | * here | |
679 | */ | |
680 | } | |
f7b879e0 | 681 | |
0e6934f2 DH |
682 | qdev_finalize_clocklist(dev); |
683 | ||
f7b879e0 MR |
684 | /* Only send event if the device had been completely realized */ |
685 | if (dev->pending_deleted_event) { | |
686 | g_assert(dev->canonical_path); | |
687 | ||
047f2ca1 | 688 | qapi_event_send_device_deleted(dev->id, dev->canonical_path); |
f7b879e0 MR |
689 | g_free(dev->canonical_path); |
690 | dev->canonical_path = NULL; | |
691 | } | |
692 | ||
163f3847 | 693 | g_free(dev->id); |
60adba37 AL |
694 | } |
695 | ||
f1fa787b | 696 | static void device_class_base_init(ObjectClass *class, const void *data) |
bce54474 PB |
697 | { |
698 | DeviceClass *klass = DEVICE_CLASS(class); | |
699 | ||
700 | /* We explicitly look up properties in the superclasses, | |
701 | * so do not propagate them to the subclasses. | |
702 | */ | |
385d8f22 | 703 | klass->props_ = NULL; |
cb9f4b28 | 704 | klass->props_count_ = 0; |
60adba37 AL |
705 | } |
706 | ||
5d5b24d0 | 707 | static void device_unparent(Object *obj) |
667d22d1 PB |
708 | { |
709 | DeviceState *dev = DEVICE(obj); | |
06f7f2bb | 710 | BusState *bus; |
667d22d1 | 711 | |
5c21ce77 | 712 | if (dev->realized) { |
dc3edf8d | 713 | qdev_unrealize(dev); |
5c21ce77 | 714 | } |
06f7f2bb PB |
715 | while (dev->num_child_bus) { |
716 | bus = QLIST_FIRST(&dev->child_bus); | |
6780a22c | 717 | object_unparent(OBJECT(bus)); |
06f7f2bb | 718 | } |
06f7f2bb | 719 | if (dev->parent_bus) { |
5d5b24d0 | 720 | bus_remove_child(dev->parent_bus, dev); |
62d7ba66 PB |
721 | object_unref(OBJECT(dev->parent_bus)); |
722 | dev->parent_bus = NULL; | |
5d5b24d0 | 723 | } |
667d22d1 PB |
724 | } |
725 | ||
107b5969 MAL |
726 | static char * |
727 | device_vmstate_if_get_id(VMStateIf *obj) | |
728 | { | |
729 | DeviceState *dev = DEVICE(obj); | |
730 | ||
731 | return qdev_get_dev_path(dev); | |
732 | } | |
733 | ||
12d1a768 | 734 | static void device_class_init(ObjectClass *class, const void *data) |
667d22d1 | 735 | { |
249d4172 | 736 | DeviceClass *dc = DEVICE_CLASS(class); |
107b5969 | 737 | VMStateIfClass *vc = VMSTATE_IF_CLASS(class); |
c11256aa | 738 | ResettableClass *rc = RESETTABLE_CLASS(class); |
249d4172 | 739 | |
5d5b24d0 | 740 | class->unparent = device_unparent; |
267a3264 IM |
741 | |
742 | /* by default all devices were considered as hotpluggable, | |
743 | * so with intent to check it in generic qdev_unplug() / | |
744 | * device_set_realized() functions make every device | |
745 | * hotpluggable. Devices that shouldn't be hotpluggable, | |
746 | * should override it in their class_init() | |
747 | */ | |
748 | dc->hotpluggable = true; | |
e90f2a8c | 749 | dc->user_creatable = true; |
107b5969 | 750 | vc->get_id = device_vmstate_if_get_id; |
c11256aa DH |
751 | rc->get_state = device_get_reset_state; |
752 | rc->child_foreach = device_reset_child_foreach; | |
753 | ||
754 | /* | |
b5fe9bf2 PM |
755 | * A NULL legacy_reset implies a three-phase reset device. Devices can |
756 | * only be reset using three-phase aware mechanisms, but we still support | |
757 | * for transitional purposes leaf classes which set the old legacy_reset | |
5fdb6cd2 | 758 | * method via device_class_set_legacy_reset(). |
c11256aa | 759 | */ |
b5fe9bf2 | 760 | dc->legacy_reset = NULL; |
c68fc935 MAL |
761 | |
762 | object_class_property_add_bool(class, "realized", | |
d2623129 | 763 | device_get_realized, device_set_realized); |
c68fc935 | 764 | object_class_property_add_bool(class, "hotpluggable", |
d2623129 | 765 | device_get_hotpluggable, NULL); |
c68fc935 | 766 | object_class_property_add_bool(class, "hotplugged", |
d2623129 | 767 | device_get_hotplugged, NULL); |
c68fc935 | 768 | object_class_property_add_link(class, "parent_bus", TYPE_BUS, |
d2623129 | 769 | offsetof(DeviceState, parent_bus), NULL, 0); |
667d22d1 PB |
770 | } |
771 | ||
5fdb6cd2 PM |
772 | static void do_legacy_reset(Object *obj, ResetType type) |
773 | { | |
774 | DeviceClass *dc = DEVICE_GET_CLASS(obj); | |
775 | ||
776 | dc->legacy_reset(DEVICE(obj)); | |
777 | } | |
778 | ||
134e0944 PM |
779 | void device_class_set_legacy_reset(DeviceClass *dc, DeviceReset dev_reset) |
780 | { | |
5fdb6cd2 PM |
781 | /* |
782 | * A legacy DeviceClass::reset has identical semantics to the | |
783 | * three-phase "hold" method, with no "enter" or "exit" | |
784 | * behaviour. Classes that use this legacy function must be leaf | |
785 | * classes that do not chain up to their parent class reset. | |
786 | * There is no mechanism for resetting a device that does not | |
787 | * use the three-phase APIs, so the only place which calls | |
788 | * the legacy_reset hook is do_legacy_reset(). | |
789 | */ | |
790 | ResettableClass *rc = RESETTABLE_CLASS(dc); | |
791 | ||
792 | rc->phases.enter = NULL; | |
793 | rc->phases.hold = do_legacy_reset; | |
794 | rc->phases.exit = NULL; | |
1000872d | 795 | dc->legacy_reset = dev_reset; |
134e0944 PM |
796 | } |
797 | ||
46795cf2 PMD |
798 | void device_class_set_parent_realize(DeviceClass *dc, |
799 | DeviceRealize dev_realize, | |
800 | DeviceRealize *parent_realize) | |
801 | { | |
802 | *parent_realize = dc->realize; | |
803 | dc->realize = dev_realize; | |
804 | } | |
805 | ||
806 | void device_class_set_parent_unrealize(DeviceClass *dc, | |
807 | DeviceUnrealize dev_unrealize, | |
808 | DeviceUnrealize *parent_unrealize) | |
809 | { | |
810 | *parent_unrealize = dc->unrealize; | |
811 | dc->unrealize = dev_unrealize; | |
812 | } | |
813 | ||
f05f6b4a PB |
814 | Object *qdev_get_machine(void) |
815 | { | |
816 | static Object *dev; | |
817 | ||
818 | if (dev == NULL) { | |
63450f32 PX |
819 | dev = object_resolve_path_component(object_get_root(), "machine"); |
820 | /* | |
821 | * Any call to this function before machine is created is treated | |
822 | * as a programming error as of now. | |
823 | */ | |
824 | assert(dev); | |
f05f6b4a PB |
825 | } |
826 | ||
827 | return dev; | |
828 | } | |
829 | ||
41fc9177 PX |
830 | Object *machine_get_container(const char *name) |
831 | { | |
832 | Object *container, *machine; | |
833 | ||
834 | machine = qdev_get_machine(); | |
835 | container = object_resolve_path_component(machine, name); | |
836 | assert(object_dynamic_cast(container, TYPE_CONTAINER)); | |
837 | ||
838 | return container; | |
839 | } | |
840 | ||
956ef499 MP |
841 | char *qdev_get_human_name(DeviceState *dev) |
842 | { | |
843 | g_assert(dev != NULL); | |
844 | ||
845 | return dev->id ? | |
846 | g_strdup(dev->id) : object_get_canonical_path(OBJECT(dev)); | |
847 | } | |
848 | ||
2f181fbd PB |
849 | static MachineInitPhase machine_phase; |
850 | ||
851 | bool phase_check(MachineInitPhase phase) | |
852 | { | |
853 | return machine_phase >= phase; | |
854 | } | |
855 | ||
856 | void phase_advance(MachineInitPhase phase) | |
857 | { | |
858 | assert(machine_phase == phase - 1); | |
859 | machine_phase = phase; | |
860 | } | |
861 | ||
8c43a6f0 | 862 | static const TypeInfo device_type_info = { |
32fea402 AL |
863 | .name = TYPE_DEVICE, |
864 | .parent = TYPE_OBJECT, | |
865 | .instance_size = sizeof(DeviceState), | |
9674bfe4 | 866 | .instance_init = device_initfn, |
99a0b036 | 867 | .instance_post_init = device_post_init, |
60adba37 | 868 | .instance_finalize = device_finalize, |
bce54474 | 869 | .class_base_init = device_class_base_init, |
667d22d1 | 870 | .class_init = device_class_init, |
32fea402 AL |
871 | .abstract = true, |
872 | .class_size = sizeof(DeviceClass), | |
2cd09e47 | 873 | .interfaces = (const InterfaceInfo[]) { |
107b5969 | 874 | { TYPE_VMSTATE_IF }, |
c11256aa | 875 | { TYPE_RESETTABLE_INTERFACE }, |
107b5969 MAL |
876 | { } |
877 | } | |
32fea402 AL |
878 | }; |
879 | ||
83f7d43a | 880 | static void qdev_register_types(void) |
32fea402 AL |
881 | { |
882 | type_register_static(&device_type_info); | |
883 | } | |
884 | ||
83f7d43a | 885 | type_init(qdev_register_types) |