]>
Commit | Line | Data |
---|---|---|
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 | |
9 | * version 2.1 of the License, or (at your option) any later version. | |
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 | /* 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 | ||
28 | #include "qemu/osdep.h" | |
29 | #include "qapi/error.h" | |
30 | #include "qapi/qapi-events-qdev.h" | |
31 | #include "qapi/qmp/qdict.h" | |
32 | #include "qapi/qmp/qerror.h" | |
33 | #include "qapi/visitor.h" | |
34 | #include "qemu/error-report.h" | |
35 | #include "qemu/option.h" | |
36 | #include "hw/irq.h" | |
37 | #include "hw/qdev-properties.h" | |
38 | #include "hw/boards.h" | |
39 | #include "hw/sysbus.h" | |
40 | #include "hw/qdev-clock.h" | |
41 | #include "migration/vmstate.h" | |
42 | #include "trace.h" | |
43 | ||
44 | static bool qdev_hot_added = false; | |
45 | bool qdev_hot_removed = false; | |
46 | ||
47 | const VMStateDescription *qdev_get_vmsd(DeviceState *dev) | |
48 | { | |
49 | DeviceClass *dc = DEVICE_GET_CLASS(dev); | |
50 | return dc->vmsd; | |
51 | } | |
52 | ||
53 | static void bus_free_bus_child(BusChild *kid) | |
54 | { | |
55 | object_unref(OBJECT(kid->child)); | |
56 | g_free(kid); | |
57 | } | |
58 | ||
59 | static void bus_remove_child(BusState *bus, DeviceState *child) | |
60 | { | |
61 | BusChild *kid; | |
62 | ||
63 | QTAILQ_FOREACH(kid, &bus->children, sibling) { | |
64 | if (kid->child == child) { | |
65 | char name[32]; | |
66 | ||
67 | snprintf(name, sizeof(name), "child[%d]", kid->index); | |
68 | QTAILQ_REMOVE_RCU(&bus->children, kid, sibling); | |
69 | ||
70 | bus->num_children--; | |
71 | ||
72 | /* This gives back ownership of kid->child back to us. */ | |
73 | object_property_del(OBJECT(bus), name); | |
74 | ||
75 | /* free the bus kid, when it is safe to do so*/ | |
76 | call_rcu(kid, bus_free_bus_child, rcu); | |
77 | break; | |
78 | } | |
79 | } | |
80 | } | |
81 | ||
82 | static void bus_add_child(BusState *bus, DeviceState *child) | |
83 | { | |
84 | char name[32]; | |
85 | BusChild *kid = g_malloc0(sizeof(*kid)); | |
86 | ||
87 | bus->num_children++; | |
88 | kid->index = bus->max_index++; | |
89 | kid->child = child; | |
90 | object_ref(OBJECT(kid->child)); | |
91 | ||
92 | QTAILQ_INSERT_HEAD_RCU(&bus->children, kid, sibling); | |
93 | ||
94 | /* This transfers ownership of kid->child to the property. */ | |
95 | snprintf(name, sizeof(name), "child[%d]", kid->index); | |
96 | object_property_add_link(OBJECT(bus), name, | |
97 | object_get_typename(OBJECT(child)), | |
98 | (Object **)&kid->child, | |
99 | NULL, /* read-only property */ | |
100 | 0); | |
101 | } | |
102 | ||
103 | static bool bus_check_address(BusState *bus, DeviceState *child, Error **errp) | |
104 | { | |
105 | BusClass *bc = BUS_GET_CLASS(bus); | |
106 | return !bc->check_address || bc->check_address(bus, child, errp); | |
107 | } | |
108 | ||
109 | bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp) | |
110 | { | |
111 | BusState *old_parent_bus = dev->parent_bus; | |
112 | DeviceClass *dc = DEVICE_GET_CLASS(dev); | |
113 | ||
114 | assert(dc->bus_type && object_dynamic_cast(OBJECT(bus), dc->bus_type)); | |
115 | ||
116 | if (!bus_check_address(bus, dev, errp)) { | |
117 | return false; | |
118 | } | |
119 | ||
120 | if (old_parent_bus) { | |
121 | trace_qdev_update_parent_bus(dev, object_get_typename(OBJECT(dev)), | |
122 | old_parent_bus, object_get_typename(OBJECT(old_parent_bus)), | |
123 | OBJECT(bus), object_get_typename(OBJECT(bus))); | |
124 | /* | |
125 | * Keep a reference to the device while it's not plugged into | |
126 | * any bus, to avoid it potentially evaporating when it is | |
127 | * dereffed in bus_remove_child(). | |
128 | * Also keep the ref of the parent bus until the end, so that | |
129 | * we can safely call resettable_change_parent() below. | |
130 | */ | |
131 | object_ref(OBJECT(dev)); | |
132 | bus_remove_child(dev->parent_bus, dev); | |
133 | } | |
134 | dev->parent_bus = bus; | |
135 | object_ref(OBJECT(bus)); | |
136 | bus_add_child(bus, dev); | |
137 | if (dev->realized) { | |
138 | resettable_change_parent(OBJECT(dev), OBJECT(bus), | |
139 | OBJECT(old_parent_bus)); | |
140 | } | |
141 | if (old_parent_bus) { | |
142 | object_unref(OBJECT(old_parent_bus)); | |
143 | object_unref(OBJECT(dev)); | |
144 | } | |
145 | return true; | |
146 | } | |
147 | ||
148 | DeviceState *qdev_new(const char *name) | |
149 | { | |
150 | ObjectClass *oc = object_class_by_name(name); | |
151 | #ifdef CONFIG_MODULES | |
152 | if (!oc) { | |
153 | int rv = module_load_qom(name, &error_fatal); | |
154 | if (rv > 0) { | |
155 | oc = object_class_by_name(name); | |
156 | } else { | |
157 | error_report("could not find a module for type '%s'", name); | |
158 | exit(1); | |
159 | } | |
160 | } | |
161 | #endif | |
162 | if (!oc) { | |
163 | error_report("unknown type '%s'", name); | |
164 | abort(); | |
165 | } | |
166 | return DEVICE(object_new(name)); | |
167 | } | |
168 | ||
169 | DeviceState *qdev_try_new(const char *name) | |
170 | { | |
171 | if (!module_object_class_by_name(name)) { | |
172 | return NULL; | |
173 | } | |
174 | return DEVICE(object_new(name)); | |
175 | } | |
176 | ||
177 | static QTAILQ_HEAD(, DeviceListener) device_listeners | |
178 | = QTAILQ_HEAD_INITIALIZER(device_listeners); | |
179 | ||
180 | enum ListenerDirection { Forward, Reverse }; | |
181 | ||
182 | #define DEVICE_LISTENER_CALL(_callback, _direction, _args...) \ | |
183 | do { \ | |
184 | DeviceListener *_listener; \ | |
185 | \ | |
186 | switch (_direction) { \ | |
187 | case Forward: \ | |
188 | QTAILQ_FOREACH(_listener, &device_listeners, link) { \ | |
189 | if (_listener->_callback) { \ | |
190 | _listener->_callback(_listener, ##_args); \ | |
191 | } \ | |
192 | } \ | |
193 | break; \ | |
194 | case Reverse: \ | |
195 | QTAILQ_FOREACH_REVERSE(_listener, &device_listeners, \ | |
196 | link) { \ | |
197 | if (_listener->_callback) { \ | |
198 | _listener->_callback(_listener, ##_args); \ | |
199 | } \ | |
200 | } \ | |
201 | break; \ | |
202 | default: \ | |
203 | abort(); \ | |
204 | } \ | |
205 | } while (0) | |
206 | ||
207 | static int device_listener_add(DeviceState *dev, void *opaque) | |
208 | { | |
209 | DEVICE_LISTENER_CALL(realize, Forward, dev); | |
210 | ||
211 | return 0; | |
212 | } | |
213 | ||
214 | void device_listener_register(DeviceListener *listener) | |
215 | { | |
216 | QTAILQ_INSERT_TAIL(&device_listeners, listener, link); | |
217 | ||
218 | qbus_walk_children(sysbus_get_default(), NULL, NULL, device_listener_add, | |
219 | NULL, NULL); | |
220 | } | |
221 | ||
222 | void device_listener_unregister(DeviceListener *listener) | |
223 | { | |
224 | QTAILQ_REMOVE(&device_listeners, listener, link); | |
225 | } | |
226 | ||
227 | bool qdev_should_hide_device(const QDict *opts, bool from_json, Error **errp) | |
228 | { | |
229 | ERRP_GUARD(); | |
230 | DeviceListener *listener; | |
231 | ||
232 | QTAILQ_FOREACH(listener, &device_listeners, link) { | |
233 | if (listener->hide_device) { | |
234 | if (listener->hide_device(listener, opts, from_json, errp)) { | |
235 | return true; | |
236 | } else if (*errp) { | |
237 | return false; | |
238 | } | |
239 | } | |
240 | } | |
241 | ||
242 | return false; | |
243 | } | |
244 | ||
245 | void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id, | |
246 | int required_for_version) | |
247 | { | |
248 | assert(!dev->realized); | |
249 | dev->instance_id_alias = alias_id; | |
250 | dev->alias_required_for_version = required_for_version; | |
251 | } | |
252 | ||
253 | void device_cold_reset(DeviceState *dev) | |
254 | { | |
255 | resettable_reset(OBJECT(dev), RESET_TYPE_COLD); | |
256 | } | |
257 | ||
258 | bool device_is_in_reset(DeviceState *dev) | |
259 | { | |
260 | return resettable_is_in_reset(OBJECT(dev)); | |
261 | } | |
262 | ||
263 | static ResettableState *device_get_reset_state(Object *obj) | |
264 | { | |
265 | DeviceState *dev = DEVICE(obj); | |
266 | return &dev->reset; | |
267 | } | |
268 | ||
269 | static void device_reset_child_foreach(Object *obj, ResettableChildCallback cb, | |
270 | void *opaque, ResetType type) | |
271 | { | |
272 | DeviceState *dev = DEVICE(obj); | |
273 | BusState *bus; | |
274 | ||
275 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
276 | cb(OBJECT(bus), opaque, type); | |
277 | } | |
278 | } | |
279 | ||
280 | bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp) | |
281 | { | |
282 | assert(!dev->realized && !dev->parent_bus); | |
283 | ||
284 | if (bus) { | |
285 | if (!qdev_set_parent_bus(dev, bus, errp)) { | |
286 | return false; | |
287 | } | |
288 | } else { | |
289 | assert(!DEVICE_GET_CLASS(dev)->bus_type); | |
290 | } | |
291 | ||
292 | return object_property_set_bool(OBJECT(dev), "realized", true, errp); | |
293 | } | |
294 | ||
295 | bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp) | |
296 | { | |
297 | bool ret; | |
298 | ||
299 | ret = qdev_realize(dev, bus, errp); | |
300 | object_unref(OBJECT(dev)); | |
301 | return ret; | |
302 | } | |
303 | ||
304 | void qdev_unrealize(DeviceState *dev) | |
305 | { | |
306 | object_property_set_bool(OBJECT(dev), "realized", false, &error_abort); | |
307 | } | |
308 | ||
309 | static int qdev_assert_realized_properly_cb(Object *obj, void *opaque) | |
310 | { | |
311 | DeviceState *dev = DEVICE(object_dynamic_cast(obj, TYPE_DEVICE)); | |
312 | DeviceClass *dc; | |
313 | ||
314 | if (dev) { | |
315 | dc = DEVICE_GET_CLASS(dev); | |
316 | assert(dev->realized); | |
317 | assert(dev->parent_bus || !dc->bus_type); | |
318 | } | |
319 | return 0; | |
320 | } | |
321 | ||
322 | void qdev_assert_realized_properly(void) | |
323 | { | |
324 | object_child_foreach_recursive(object_get_root(), | |
325 | qdev_assert_realized_properly_cb, NULL); | |
326 | } | |
327 | ||
328 | bool qdev_machine_modified(void) | |
329 | { | |
330 | return qdev_hot_added || qdev_hot_removed; | |
331 | } | |
332 | ||
333 | BusState *qdev_get_parent_bus(DeviceState *dev) | |
334 | { | |
335 | return dev->parent_bus; | |
336 | } | |
337 | ||
338 | BusState *qdev_get_child_bus(DeviceState *dev, const char *name) | |
339 | { | |
340 | BusState *bus; | |
341 | Object *child = object_resolve_path_component(OBJECT(dev), name); | |
342 | ||
343 | bus = (BusState *)object_dynamic_cast(child, TYPE_BUS); | |
344 | if (bus) { | |
345 | return bus; | |
346 | } | |
347 | ||
348 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
349 | if (strcmp(name, bus->name) == 0) { | |
350 | return bus; | |
351 | } | |
352 | } | |
353 | return NULL; | |
354 | } | |
355 | ||
356 | int qdev_walk_children(DeviceState *dev, | |
357 | qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, | |
358 | qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, | |
359 | void *opaque) | |
360 | { | |
361 | BusState *bus; | |
362 | int err; | |
363 | ||
364 | if (pre_devfn) { | |
365 | err = pre_devfn(dev, opaque); | |
366 | if (err) { | |
367 | return err; | |
368 | } | |
369 | } | |
370 | ||
371 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
372 | err = qbus_walk_children(bus, pre_devfn, pre_busfn, | |
373 | post_devfn, post_busfn, opaque); | |
374 | if (err < 0) { | |
375 | return err; | |
376 | } | |
377 | } | |
378 | ||
379 | if (post_devfn) { | |
380 | err = post_devfn(dev, opaque); | |
381 | if (err) { | |
382 | return err; | |
383 | } | |
384 | } | |
385 | ||
386 | return 0; | |
387 | } | |
388 | ||
389 | DeviceState *qdev_find_recursive(BusState *bus, const char *id) | |
390 | { | |
391 | BusChild *kid; | |
392 | DeviceState *ret; | |
393 | BusState *child; | |
394 | ||
395 | WITH_RCU_READ_LOCK_GUARD() { | |
396 | QTAILQ_FOREACH_RCU(kid, &bus->children, sibling) { | |
397 | DeviceState *dev = kid->child; | |
398 | ||
399 | if (dev->id && strcmp(dev->id, id) == 0) { | |
400 | return dev; | |
401 | } | |
402 | ||
403 | QLIST_FOREACH(child, &dev->child_bus, sibling) { | |
404 | ret = qdev_find_recursive(child, id); | |
405 | if (ret) { | |
406 | return ret; | |
407 | } | |
408 | } | |
409 | } | |
410 | } | |
411 | return NULL; | |
412 | } | |
413 | ||
414 | char *qdev_get_dev_path(DeviceState *dev) | |
415 | { | |
416 | BusClass *bc; | |
417 | ||
418 | if (!dev || !dev->parent_bus) { | |
419 | return NULL; | |
420 | } | |
421 | ||
422 | bc = BUS_GET_CLASS(dev->parent_bus); | |
423 | if (bc->get_dev_path) { | |
424 | return bc->get_dev_path(dev); | |
425 | } | |
426 | ||
427 | return NULL; | |
428 | } | |
429 | ||
430 | void qdev_add_unplug_blocker(DeviceState *dev, Error *reason) | |
431 | { | |
432 | dev->unplug_blockers = g_slist_prepend(dev->unplug_blockers, reason); | |
433 | } | |
434 | ||
435 | void qdev_del_unplug_blocker(DeviceState *dev, Error *reason) | |
436 | { | |
437 | dev->unplug_blockers = g_slist_remove(dev->unplug_blockers, reason); | |
438 | } | |
439 | ||
440 | bool qdev_unplug_blocked(DeviceState *dev, Error **errp) | |
441 | { | |
442 | if (dev->unplug_blockers) { | |
443 | error_propagate(errp, error_copy(dev->unplug_blockers->data)); | |
444 | return true; | |
445 | } | |
446 | ||
447 | return false; | |
448 | } | |
449 | ||
450 | static bool device_get_realized(Object *obj, Error **errp) | |
451 | { | |
452 | DeviceState *dev = DEVICE(obj); | |
453 | return dev->realized; | |
454 | } | |
455 | ||
456 | static bool check_only_migratable(Object *obj, Error **errp) | |
457 | { | |
458 | DeviceClass *dc = DEVICE_GET_CLASS(obj); | |
459 | ||
460 | if (!vmstate_check_only_migratable(dc->vmsd)) { | |
461 | error_setg(errp, "Device %s is not migratable, but " | |
462 | "--only-migratable was specified", | |
463 | object_get_typename(obj)); | |
464 | return false; | |
465 | } | |
466 | ||
467 | return true; | |
468 | } | |
469 | ||
470 | static void device_set_realized(Object *obj, bool value, Error **errp) | |
471 | { | |
472 | DeviceState *dev = DEVICE(obj); | |
473 | DeviceClass *dc = DEVICE_GET_CLASS(dev); | |
474 | HotplugHandler *hotplug_ctrl; | |
475 | BusState *bus; | |
476 | NamedClockList *ncl; | |
477 | Error *local_err = NULL; | |
478 | bool unattached_parent = false; | |
479 | static int unattached_count; | |
480 | ||
481 | if (dev->hotplugged && !dc->hotpluggable) { | |
482 | error_setg(errp, QERR_DEVICE_NO_HOTPLUG, object_get_typename(obj)); | |
483 | return; | |
484 | } | |
485 | ||
486 | if (value && !dev->realized) { | |
487 | if (!check_only_migratable(obj, errp)) { | |
488 | goto fail; | |
489 | } | |
490 | ||
491 | if (!obj->parent) { | |
492 | gchar *name = g_strdup_printf("device[%d]", unattached_count++); | |
493 | ||
494 | object_property_add_child(container_get(qdev_get_machine(), | |
495 | "/unattached"), | |
496 | name, obj); | |
497 | unattached_parent = true; | |
498 | g_free(name); | |
499 | } | |
500 | ||
501 | hotplug_ctrl = qdev_get_hotplug_handler(dev); | |
502 | if (hotplug_ctrl) { | |
503 | hotplug_handler_pre_plug(hotplug_ctrl, dev, &local_err); | |
504 | if (local_err != NULL) { | |
505 | goto fail; | |
506 | } | |
507 | } | |
508 | ||
509 | if (dc->realize) { | |
510 | dc->realize(dev, &local_err); | |
511 | if (local_err != NULL) { | |
512 | goto fail; | |
513 | } | |
514 | } | |
515 | ||
516 | DEVICE_LISTENER_CALL(realize, Forward, dev); | |
517 | ||
518 | /* | |
519 | * always free/re-initialize here since the value cannot be cleaned up | |
520 | * in device_unrealize due to its usage later on in the unplug path | |
521 | */ | |
522 | g_free(dev->canonical_path); | |
523 | dev->canonical_path = object_get_canonical_path(OBJECT(dev)); | |
524 | QLIST_FOREACH(ncl, &dev->clocks, node) { | |
525 | if (ncl->alias) { | |
526 | continue; | |
527 | } else { | |
528 | clock_setup_canonical_path(ncl->clock); | |
529 | } | |
530 | } | |
531 | ||
532 | if (qdev_get_vmsd(dev)) { | |
533 | if (vmstate_register_with_alias_id(VMSTATE_IF(dev), | |
534 | VMSTATE_INSTANCE_ID_ANY, | |
535 | qdev_get_vmsd(dev), dev, | |
536 | dev->instance_id_alias, | |
537 | dev->alias_required_for_version, | |
538 | &local_err) < 0) { | |
539 | goto post_realize_fail; | |
540 | } | |
541 | } | |
542 | ||
543 | /* | |
544 | * Clear the reset state, in case the object was previously unrealized | |
545 | * with a dirty state. | |
546 | */ | |
547 | resettable_state_clear(&dev->reset); | |
548 | ||
549 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
550 | if (!qbus_realize(bus, errp)) { | |
551 | goto child_realize_fail; | |
552 | } | |
553 | } | |
554 | if (dev->hotplugged) { | |
555 | /* | |
556 | * Reset the device, as well as its subtree which, at this point, | |
557 | * should be realized too. | |
558 | */ | |
559 | resettable_assert_reset(OBJECT(dev), RESET_TYPE_COLD); | |
560 | resettable_change_parent(OBJECT(dev), OBJECT(dev->parent_bus), | |
561 | NULL); | |
562 | resettable_release_reset(OBJECT(dev), RESET_TYPE_COLD); | |
563 | } | |
564 | dev->pending_deleted_event = false; | |
565 | ||
566 | if (hotplug_ctrl) { | |
567 | hotplug_handler_plug(hotplug_ctrl, dev, &local_err); | |
568 | if (local_err != NULL) { | |
569 | goto child_realize_fail; | |
570 | } | |
571 | } | |
572 | ||
573 | qatomic_store_release(&dev->realized, value); | |
574 | ||
575 | } else if (!value && dev->realized) { | |
576 | ||
577 | /* | |
578 | * Change the value so that any concurrent users are aware | |
579 | * that the device is going to be unrealized | |
580 | * | |
581 | * TODO: change .realized property to enum that states | |
582 | * each phase of the device realization/unrealization | |
583 | */ | |
584 | ||
585 | qatomic_set(&dev->realized, value); | |
586 | /* | |
587 | * Ensure that concurrent users see this update prior to | |
588 | * any other changes done by unrealize. | |
589 | */ | |
590 | smp_wmb(); | |
591 | ||
592 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
593 | qbus_unrealize(bus); | |
594 | } | |
595 | if (qdev_get_vmsd(dev)) { | |
596 | vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); | |
597 | } | |
598 | if (dc->unrealize) { | |
599 | dc->unrealize(dev); | |
600 | } | |
601 | dev->pending_deleted_event = true; | |
602 | DEVICE_LISTENER_CALL(unrealize, Reverse, dev); | |
603 | } | |
604 | ||
605 | assert(local_err == NULL); | |
606 | return; | |
607 | ||
608 | child_realize_fail: | |
609 | QLIST_FOREACH(bus, &dev->child_bus, sibling) { | |
610 | qbus_unrealize(bus); | |
611 | } | |
612 | ||
613 | if (qdev_get_vmsd(dev)) { | |
614 | vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev); | |
615 | } | |
616 | ||
617 | post_realize_fail: | |
618 | g_free(dev->canonical_path); | |
619 | dev->canonical_path = NULL; | |
620 | if (dc->unrealize) { | |
621 | dc->unrealize(dev); | |
622 | } | |
623 | ||
624 | fail: | |
625 | error_propagate(errp, local_err); | |
626 | if (unattached_parent) { | |
627 | /* | |
628 | * Beware, this doesn't just revert | |
629 | * object_property_add_child(), it also runs bus_remove()! | |
630 | */ | |
631 | object_unparent(OBJECT(dev)); | |
632 | unattached_count--; | |
633 | } | |
634 | } | |
635 | ||
636 | static bool device_get_hotpluggable(Object *obj, Error **errp) | |
637 | { | |
638 | DeviceClass *dc = DEVICE_GET_CLASS(obj); | |
639 | DeviceState *dev = DEVICE(obj); | |
640 | ||
641 | return dc->hotpluggable && (dev->parent_bus == NULL || | |
642 | qbus_is_hotpluggable(dev->parent_bus)); | |
643 | } | |
644 | ||
645 | static bool device_get_hotplugged(Object *obj, Error **errp) | |
646 | { | |
647 | DeviceState *dev = DEVICE(obj); | |
648 | ||
649 | return dev->hotplugged; | |
650 | } | |
651 | ||
652 | static void device_initfn(Object *obj) | |
653 | { | |
654 | DeviceState *dev = DEVICE(obj); | |
655 | ||
656 | if (phase_check(PHASE_MACHINE_READY)) { | |
657 | dev->hotplugged = 1; | |
658 | qdev_hot_added = true; | |
659 | } | |
660 | ||
661 | dev->instance_id_alias = -1; | |
662 | dev->realized = false; | |
663 | dev->allow_unplug_during_migration = false; | |
664 | ||
665 | QLIST_INIT(&dev->gpios); | |
666 | QLIST_INIT(&dev->clocks); | |
667 | } | |
668 | ||
669 | static void device_post_init(Object *obj) | |
670 | { | |
671 | /* | |
672 | * Note: ordered so that the user's global properties take | |
673 | * precedence. | |
674 | */ | |
675 | object_apply_compat_props(obj); | |
676 | qdev_prop_set_globals(DEVICE(obj)); | |
677 | } | |
678 | ||
679 | /* Unlink device from bus and free the structure. */ | |
680 | static void device_finalize(Object *obj) | |
681 | { | |
682 | NamedGPIOList *ngl, *next; | |
683 | ||
684 | DeviceState *dev = DEVICE(obj); | |
685 | ||
686 | g_assert(!dev->unplug_blockers); | |
687 | ||
688 | QLIST_FOREACH_SAFE(ngl, &dev->gpios, node, next) { | |
689 | QLIST_REMOVE(ngl, node); | |
690 | qemu_free_irqs(ngl->in, ngl->num_in); | |
691 | g_free(ngl->name); | |
692 | g_free(ngl); | |
693 | /* ngl->out irqs are owned by the other end and should not be freed | |
694 | * here | |
695 | */ | |
696 | } | |
697 | ||
698 | qdev_finalize_clocklist(dev); | |
699 | ||
700 | /* Only send event if the device had been completely realized */ | |
701 | if (dev->pending_deleted_event) { | |
702 | g_assert(dev->canonical_path); | |
703 | ||
704 | qapi_event_send_device_deleted(dev->id, dev->canonical_path); | |
705 | g_free(dev->canonical_path); | |
706 | dev->canonical_path = NULL; | |
707 | } | |
708 | ||
709 | qobject_unref(dev->opts); | |
710 | g_free(dev->id); | |
711 | } | |
712 | ||
713 | static void device_class_base_init(ObjectClass *class, void *data) | |
714 | { | |
715 | DeviceClass *klass = DEVICE_CLASS(class); | |
716 | ||
717 | /* We explicitly look up properties in the superclasses, | |
718 | * so do not propagate them to the subclasses. | |
719 | */ | |
720 | klass->props_ = NULL; | |
721 | } | |
722 | ||
723 | static void device_unparent(Object *obj) | |
724 | { | |
725 | DeviceState *dev = DEVICE(obj); | |
726 | BusState *bus; | |
727 | ||
728 | if (dev->realized) { | |
729 | qdev_unrealize(dev); | |
730 | } | |
731 | while (dev->num_child_bus) { | |
732 | bus = QLIST_FIRST(&dev->child_bus); | |
733 | object_unparent(OBJECT(bus)); | |
734 | } | |
735 | if (dev->parent_bus) { | |
736 | bus_remove_child(dev->parent_bus, dev); | |
737 | object_unref(OBJECT(dev->parent_bus)); | |
738 | dev->parent_bus = NULL; | |
739 | } | |
740 | } | |
741 | ||
742 | static char * | |
743 | device_vmstate_if_get_id(VMStateIf *obj) | |
744 | { | |
745 | DeviceState *dev = DEVICE(obj); | |
746 | ||
747 | return qdev_get_dev_path(dev); | |
748 | } | |
749 | ||
750 | /** | |
751 | * device_phases_reset: | |
752 | * Transition reset method for devices to allow moving | |
753 | * smoothly from legacy reset method to multi-phases | |
754 | */ | |
755 | static void device_phases_reset(DeviceState *dev) | |
756 | { | |
757 | ResettableClass *rc = RESETTABLE_GET_CLASS(dev); | |
758 | ||
759 | if (rc->phases.enter) { | |
760 | rc->phases.enter(OBJECT(dev), RESET_TYPE_COLD); | |
761 | } | |
762 | if (rc->phases.hold) { | |
763 | rc->phases.hold(OBJECT(dev)); | |
764 | } | |
765 | if (rc->phases.exit) { | |
766 | rc->phases.exit(OBJECT(dev)); | |
767 | } | |
768 | } | |
769 | ||
770 | static void device_transitional_reset(Object *obj) | |
771 | { | |
772 | DeviceClass *dc = DEVICE_GET_CLASS(obj); | |
773 | ||
774 | /* | |
775 | * This will call either @device_phases_reset (for multi-phases transitioned | |
776 | * devices) or a device's specific method for not-yet transitioned devices. | |
777 | * In both case, it does not reset children. | |
778 | */ | |
779 | if (dc->reset) { | |
780 | dc->reset(DEVICE(obj)); | |
781 | } | |
782 | } | |
783 | ||
784 | /** | |
785 | * device_get_transitional_reset: | |
786 | * check if the device's class is ready for multi-phase | |
787 | */ | |
788 | static ResettableTrFunction device_get_transitional_reset(Object *obj) | |
789 | { | |
790 | DeviceClass *dc = DEVICE_GET_CLASS(obj); | |
791 | if (dc->reset != device_phases_reset) { | |
792 | /* | |
793 | * dc->reset has been overridden by a subclass, | |
794 | * the device is not ready for multi phase yet. | |
795 | */ | |
796 | return device_transitional_reset; | |
797 | } | |
798 | return NULL; | |
799 | } | |
800 | ||
801 | static void device_class_init(ObjectClass *class, void *data) | |
802 | { | |
803 | DeviceClass *dc = DEVICE_CLASS(class); | |
804 | VMStateIfClass *vc = VMSTATE_IF_CLASS(class); | |
805 | ResettableClass *rc = RESETTABLE_CLASS(class); | |
806 | ||
807 | class->unparent = device_unparent; | |
808 | ||
809 | /* by default all devices were considered as hotpluggable, | |
810 | * so with intent to check it in generic qdev_unplug() / | |
811 | * device_set_realized() functions make every device | |
812 | * hotpluggable. Devices that shouldn't be hotpluggable, | |
813 | * should override it in their class_init() | |
814 | */ | |
815 | dc->hotpluggable = true; | |
816 | dc->user_creatable = true; | |
817 | vc->get_id = device_vmstate_if_get_id; | |
818 | rc->get_state = device_get_reset_state; | |
819 | rc->child_foreach = device_reset_child_foreach; | |
820 | ||
821 | /* | |
822 | * @device_phases_reset is put as the default reset method below, allowing | |
823 | * to do the multi-phase transition from base classes to leaf classes. It | |
824 | * allows a legacy-reset Device class to extend a multi-phases-reset | |
825 | * Device class for the following reason: | |
826 | * + If a base class B has been moved to multi-phase, then it does not | |
827 | * override this default reset method and may have defined phase methods. | |
828 | * + A child class C (extending class B) which uses | |
829 | * device_class_set_parent_reset() (or similar means) to override the | |
830 | * reset method will still work as expected. @device_phases_reset function | |
831 | * will be registered as the parent reset method and effectively call | |
832 | * parent reset phases. | |
833 | */ | |
834 | dc->reset = device_phases_reset; | |
835 | rc->get_transitional_function = device_get_transitional_reset; | |
836 | ||
837 | object_class_property_add_bool(class, "realized", | |
838 | device_get_realized, device_set_realized); | |
839 | object_class_property_add_bool(class, "hotpluggable", | |
840 | device_get_hotpluggable, NULL); | |
841 | object_class_property_add_bool(class, "hotplugged", | |
842 | device_get_hotplugged, NULL); | |
843 | object_class_property_add_link(class, "parent_bus", TYPE_BUS, | |
844 | offsetof(DeviceState, parent_bus), NULL, 0); | |
845 | } | |
846 | ||
847 | void device_class_set_parent_reset(DeviceClass *dc, | |
848 | DeviceReset dev_reset, | |
849 | DeviceReset *parent_reset) | |
850 | { | |
851 | *parent_reset = dc->reset; | |
852 | dc->reset = dev_reset; | |
853 | } | |
854 | ||
855 | void device_class_set_parent_realize(DeviceClass *dc, | |
856 | DeviceRealize dev_realize, | |
857 | DeviceRealize *parent_realize) | |
858 | { | |
859 | *parent_realize = dc->realize; | |
860 | dc->realize = dev_realize; | |
861 | } | |
862 | ||
863 | void device_class_set_parent_unrealize(DeviceClass *dc, | |
864 | DeviceUnrealize dev_unrealize, | |
865 | DeviceUnrealize *parent_unrealize) | |
866 | { | |
867 | *parent_unrealize = dc->unrealize; | |
868 | dc->unrealize = dev_unrealize; | |
869 | } | |
870 | ||
871 | Object *qdev_get_machine(void) | |
872 | { | |
873 | static Object *dev; | |
874 | ||
875 | if (dev == NULL) { | |
876 | dev = container_get(object_get_root(), "/machine"); | |
877 | } | |
878 | ||
879 | return dev; | |
880 | } | |
881 | ||
882 | static MachineInitPhase machine_phase; | |
883 | ||
884 | bool phase_check(MachineInitPhase phase) | |
885 | { | |
886 | return machine_phase >= phase; | |
887 | } | |
888 | ||
889 | void phase_advance(MachineInitPhase phase) | |
890 | { | |
891 | assert(machine_phase == phase - 1); | |
892 | machine_phase = phase; | |
893 | } | |
894 | ||
895 | static const TypeInfo device_type_info = { | |
896 | .name = TYPE_DEVICE, | |
897 | .parent = TYPE_OBJECT, | |
898 | .instance_size = sizeof(DeviceState), | |
899 | .instance_init = device_initfn, | |
900 | .instance_post_init = device_post_init, | |
901 | .instance_finalize = device_finalize, | |
902 | .class_base_init = device_class_base_init, | |
903 | .class_init = device_class_init, | |
904 | .abstract = true, | |
905 | .class_size = sizeof(DeviceClass), | |
906 | .interfaces = (InterfaceInfo[]) { | |
907 | { TYPE_VMSTATE_IF }, | |
908 | { TYPE_RESETTABLE_INTERFACE }, | |
909 | { } | |
910 | } | |
911 | }; | |
912 | ||
913 | static void qdev_register_types(void) | |
914 | { | |
915 | type_register_static(&device_type_info); | |
916 | } | |
917 | ||
918 | type_init(qdev_register_types) |