summaryrefslogtreecommitdiffstats
path: root/hw/core
diff options
context:
space:
mode:
authorPeter Maydell2020-06-16 12:48:22 +0200
committerPeter Maydell2020-06-16 12:48:23 +0200
commit6675a653d2e57ab09c32c0ea7b44a1d6c40a7f58 (patch)
treef111fb308c19e2b4f2dd8b8482e057b4f3490362 /hw/core
parentMerge remote-tracking branch 'remotes/amarkovic/tags/mips-queue-jun-15-2020' ... (diff)
parentMAINTAINERS: Make section QOM cover hw/core/*bus.c as well (diff)
downloadqemu-6675a653d2e57ab09c32c0ea7b44a1d6c40a7f58.tar.gz
qemu-6675a653d2e57ab09c32c0ea7b44a1d6c40a7f58.tar.xz
qemu-6675a653d2e57ab09c32c0ea7b44a1d6c40a7f58.zip
Merge remote-tracking branch 'remotes/armbru/tags/pull-qom-2020-06-15' into staging
QOM patches for 2020-06-15 # gpg: Signature made Mon 15 Jun 2020 21:07:19 BST # gpg: using RSA key 354BC8B3D7EB2A6B68674E5F3870B400EB918653 # gpg: issuer "armbru@redhat.com" # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" [full] # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" [full] # Primary key fingerprint: 354B C8B3 D7EB 2A6B 6867 4E5F 3870 B400 EB91 8653 * remotes/armbru/tags/pull-qom-2020-06-15: (84 commits) MAINTAINERS: Make section QOM cover hw/core/*bus.c as well qdev: qdev_init_nofail() is now unused, drop qdev: Convert bus-less devices to qdev_realize() with Coccinelle qdev: Use qdev_realize() in qdev_device_add() qdev: Make qdev_realize() support bus-less devices s390x/event-facility: Simplify creation of SCLP event devices microbit: Eliminate two local variables in microbit_init() sysbus: sysbus_init_child_obj() is now unused, drop sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 4 sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 3 sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 2 sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 1 qdev: Drop qdev_realize() support for null bus sysbus: Convert to sysbus_realize() etc. with Coccinelle sysbus: New sysbus_realize(), sysbus_realize_and_unref() sysbus: Tidy up sysbus_init_child_obj()'s @childsize arg, part 2 hw/arm/armsse: Pass correct child size to sysbus_init_child_obj() sysbus: Tidy up sysbus_init_child_obj()'s @childsize arg, part 1 microbit: Tidy up sysbus_init_child_obj() @child argument sysbus: Drop useless OBJECT() in sysbus_init_child_obj() calls ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/core')
-rw-r--r--hw/core/bus.c23
-rw-r--r--hw/core/cpu.c2
-rw-r--r--hw/core/qdev.c147
-rw-r--r--hw/core/sysbus.c27
4 files changed, 116 insertions, 83 deletions
diff --git a/hw/core/bus.c b/hw/core/bus.c
index 50924793ac..6cc28b334e 100644
--- a/hw/core/bus.c
+++ b/hw/core/bus.c
@@ -95,7 +95,7 @@ static void bus_reset_child_foreach(Object *obj, ResettableChildCallback cb,
}
}
-static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
+static void qbus_init(BusState *bus, DeviceState *parent, const char *name)
{
const char *typename = object_get_typename(OBJECT(bus));
BusClass *bc;
@@ -151,7 +151,7 @@ void qbus_create_inplace(void *bus, size_t size, const char *typename,
DeviceState *parent, const char *name)
{
object_initialize(bus, size, typename);
- qbus_realize(bus, parent, name);
+ qbus_init(bus, parent, name);
}
BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
@@ -159,11 +159,25 @@ BusState *qbus_create(const char *typename, DeviceState *parent, const char *nam
BusState *bus;
bus = BUS(object_new(typename));
- qbus_realize(bus, parent, name);
+ qbus_init(bus, parent, name);
return bus;
}
+bool qbus_realize(BusState *bus, Error **errp)
+{
+ Error *err = NULL;
+
+ object_property_set_bool(OBJECT(bus), true, "realized", &err);
+ error_propagate(errp, err);
+ return !err;
+}
+
+void qbus_unrealize(BusState *bus)
+{
+ object_property_set_bool(OBJECT(bus), false, "realized", &error_abort);
+}
+
static bool bus_get_realized(Object *obj, Error **errp)
{
BusState *bus = BUS(obj);
@@ -186,8 +200,7 @@ static void bus_set_realized(Object *obj, bool value, Error **errp)
} else if (!value && bus->realized) {
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
- object_property_set_bool(OBJECT(dev), false, "realized",
- &error_abort);
+ qdev_unrealize(dev);
}
if (bc->unrealize) {
bc->unrealize(bus);
diff --git a/hw/core/cpu.c b/hw/core/cpu.c
index f31ec48ee6..4d5438b70e 100644
--- a/hw/core/cpu.c
+++ b/hw/core/cpu.c
@@ -59,7 +59,7 @@ CPUState *cpu_create(const char *typename)
{
Error *err = NULL;
CPUState *cpu = CPU(object_new(typename));
- object_property_set_bool(OBJECT(cpu), true, "realized", &err);
+ qdev_realize(DEVICE(cpu), NULL, &err);
if (err != NULL) {
error_report_err(err);
object_unref(OBJECT(cpu));
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 9e5538aeae..2131c7f951 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -97,6 +97,9 @@ static void bus_add_child(BusState *bus, DeviceState *child)
void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
{
BusState *old_parent_bus = dev->parent_bus;
+ DeviceClass *dc = DEVICE_GET_CLASS(dev);
+
+ assert(dc->bus_type && object_dynamic_cast(OBJECT(bus), dc->bus_type));
if (old_parent_bus) {
trace_qdev_update_parent_bus(dev, object_get_typename(OBJECT(dev)),
@@ -125,52 +128,30 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
}
}
-/* Create a new device. This only initializes the device state
- structure and allows properties to be set. The device still needs
- to be realized. See qdev-core.h. */
-DeviceState *qdev_create(BusState *bus, const char *name)
+/*
+ * Create a device on the heap.
+ * A type @name must exist.
+ * This only initializes the device state structure and allows
+ * properties to be set. The device still needs to be realized. See
+ * qdev-core.h.
+ */
+DeviceState *qdev_new(const char *name)
{
- DeviceState *dev;
-
- dev = qdev_try_create(bus, name);
- if (!dev) {
- if (bus) {
- error_report("Unknown device '%s' for bus '%s'", name,
- object_get_typename(OBJECT(bus)));
- } else {
- error_report("Unknown device '%s' for default sysbus", name);
- }
- abort();
- }
-
- return dev;
+ return DEVICE(object_new(name));
}
-DeviceState *qdev_try_create(BusState *bus, const char *type)
+/*
+ * Try to create a device on the heap.
+ * This is like qdev_new(), except it returns %NULL when type @name
+ * does not exist.
+ */
+DeviceState *qdev_try_new(const char *name)
{
- DeviceState *dev;
-
- if (object_class_by_name(type) == NULL) {
+ if (!object_class_by_name(name)) {
return NULL;
}
- dev = DEVICE(object_new(type));
- if (!dev) {
- return NULL;
- }
-
- if (!bus) {
- /* Assert that the device really is a SysBusDevice before
- * we put it onto the sysbus. Non-sysbus devices which aren't
- * being put onto a bus should be created with object_new(TYPE_FOO),
- * not qdev_create(NULL, TYPE_FOO).
- */
- g_assert(object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE));
- bus = sysbus_get_default();
- }
- qdev_set_parent_bus(dev, bus);
- object_unref(OBJECT(dev));
- return dev;
+ return DEVICE(object_new(name));
}
static QTAILQ_HEAD(, DeviceListener) device_listeners
@@ -392,36 +373,71 @@ static void device_reset_child_foreach(Object *obj, ResettableChildCallback cb,
void qdev_simple_device_unplug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- object_property_set_bool(OBJECT(dev), false, "realized", &error_abort);
+ qdev_unrealize(dev);
}
/*
* Realize @dev.
- * Device properties should be set before calling this function. IRQs
- * and MMIO regions should be connected/mapped after calling this
- * function.
- * On failure, report an error with error_report() and terminate the
- * program. This is okay during machine creation. Don't use for
- * hotplug, because there callers need to recover from failure.
- * Exception: if you know the device's init() callback can't fail,
- * then qdev_init_nofail() can't fail either, and is therefore usable
- * even then. But relying on the device implementation that way is
- * somewhat unclean, and best avoided.
+ * @dev must not be plugged into a bus.
+ * If @bus, plug @dev into @bus. This takes a reference to @dev.
+ * If @dev has no QOM parent, make one up, taking another reference.
+ * On success, return true.
+ * On failure, store an error through @errp and return false.
*/
-void qdev_init_nofail(DeviceState *dev)
+bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp)
{
Error *err = NULL;
- assert(!dev->realized);
+ assert(!dev->realized && !dev->parent_bus);
+
+ if (bus) {
+ qdev_set_parent_bus(dev, bus);
+ } else {
+ assert(!DEVICE_GET_CLASS(dev)->bus_type);
+ }
- object_ref(OBJECT(dev));
object_property_set_bool(OBJECT(dev), true, "realized", &err);
if (err) {
- error_reportf_err(err, "Initialization of device %s failed: ",
- object_get_typename(OBJECT(dev)));
- exit(1);
+ error_propagate(errp, err);
}
+ return !err;
+}
+
+/*
+ * Realize @dev and drop a reference.
+ * This is like qdev_realize(), except the caller must hold a
+ * (private) reference, which is dropped on return regardless of
+ * success or failure. Intended use:
+ * dev = qdev_new();
+ * [...]
+ * qdev_realize_and_unref(dev, bus, errp);
+ * Now @dev can go away without further ado.
+ */
+bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp)
+{
+ bool ret;
+
+ ret = qdev_realize(dev, bus, errp);
object_unref(OBJECT(dev));
+ return ret;
+}
+
+void qdev_unrealize(DeviceState *dev)
+{
+ object_property_set_bool(OBJECT(dev), false, "realized", &error_abort);
+}
+
+static int qdev_assert_realized_properly(Object *obj, void *opaque)
+{
+ DeviceState *dev = DEVICE(object_dynamic_cast(obj, TYPE_DEVICE));
+ DeviceClass *dc;
+
+ if (dev) {
+ dc = DEVICE_GET_CLASS(dev);
+ assert(dev->realized);
+ assert(dev->parent_bus || !dc->bus_type);
+ }
+ return 0;
}
void qdev_machine_creation_done(void)
@@ -431,6 +447,9 @@ void qdev_machine_creation_done(void)
* only create hotpluggable devices
*/
qdev_hotplug = true;
+
+ object_child_foreach_recursive(object_get_root(),
+ qdev_assert_realized_properly, NULL);
}
bool qdev_machine_modified(void)
@@ -919,9 +938,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
resettable_state_clear(&dev->reset);
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
- object_property_set_bool(OBJECT(bus), true, "realized",
- &local_err);
- if (local_err != NULL) {
+ if (!qbus_realize(bus, errp)) {
goto child_realize_fail;
}
}
@@ -946,8 +963,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
} else if (!value && dev->realized) {
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
- object_property_set_bool(OBJECT(bus), false, "realized",
- &error_abort);
+ qbus_unrealize(bus);
}
if (qdev_get_vmsd(dev)) {
vmstate_unregister(VMSTATE_IF(dev), qdev_get_vmsd(dev), dev);
@@ -965,8 +981,7 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
child_realize_fail:
QLIST_FOREACH(bus, &dev->child_bus, sibling) {
- object_property_set_bool(OBJECT(bus), false, "realized",
- &error_abort);
+ qbus_unrealize(bus);
}
if (qdev_get_vmsd(dev)) {
@@ -983,6 +998,10 @@ post_realize_fail:
fail:
error_propagate(errp, local_err);
if (unattached_parent) {
+ /*
+ * Beware, this doesn't just revert
+ * object_property_add_child(), it also runs bus_remove()!
+ */
object_unparent(OBJECT(dev));
unattached_count--;
}
@@ -1078,7 +1097,7 @@ static void device_unparent(Object *obj)
BusState *bus;
if (dev->realized) {
- object_property_set_bool(obj, false, "realized", &error_abort);
+ qdev_unrealize(dev);
}
while (dev->num_child_bus) {
bus = QLIST_FIRST(&dev->child_bus);
diff --git a/hw/core/sysbus.c b/hw/core/sysbus.c
index 08b0311c5f..70239b7e7d 100644
--- a/hw/core/sysbus.c
+++ b/hw/core/sysbus.c
@@ -217,7 +217,7 @@ void sysbus_init_ioports(SysBusDevice *dev, uint32_t ioport, uint32_t size)
* from being set to NULL to break the normal init/realize
* of some devices.
*/
-static void sysbus_realize(DeviceState *dev, Error **errp)
+static void sysbus_device_realize(DeviceState *dev, Error **errp)
{
}
@@ -230,9 +230,9 @@ DeviceState *sysbus_create_varargs(const char *name,
qemu_irq irq;
int n;
- dev = qdev_create(NULL, name);
+ dev = qdev_new(name);
s = SYS_BUS_DEVICE(dev);
- qdev_init_nofail(dev);
+ sysbus_realize_and_unref(s, &error_fatal);
if (addr != (hwaddr)-1) {
sysbus_mmio_map(s, 0, addr);
}
@@ -250,6 +250,16 @@ DeviceState *sysbus_create_varargs(const char *name,
return dev;
}
+bool sysbus_realize(SysBusDevice *dev, Error **errp)
+{
+ return qdev_realize(DEVICE(dev), sysbus_get_default(), errp);
+}
+
+bool sysbus_realize_and_unref(SysBusDevice *dev, Error **errp)
+{
+ return qdev_realize_and_unref(DEVICE(dev), sysbus_get_default(), errp);
+}
+
static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent)
{
SysBusDevice *s = SYS_BUS_DEVICE(dev);
@@ -301,7 +311,7 @@ MemoryRegion *sysbus_address_space(SysBusDevice *dev)
static void sysbus_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
- k->realize = sysbus_realize;
+ k->realize = sysbus_device_realize;
k->bus_type = TYPE_SYSTEM_BUS;
/*
* device_add plugs devices into a suitable bus. For "real" buses,
@@ -325,7 +335,6 @@ static const TypeInfo sysbus_device_type_info = {
.class_init = sysbus_device_class_init,
};
-/* This is a nasty hack to allow passing a NULL bus to qdev_create. */
static BusState *main_system_bus;
static void main_system_bus_create(void)
@@ -346,14 +355,6 @@ BusState *sysbus_get_default(void)
return main_system_bus;
}
-void sysbus_init_child_obj(Object *parent, const char *childname, void *child,
- size_t childsize, const char *childtype)
-{
- object_initialize_child(parent, childname, child, childsize, childtype,
- &error_abort, NULL);
- qdev_set_parent_bus(DEVICE(child), sysbus_get_default());
-}
-
static void sysbus_register_types(void)
{
type_register_static(&system_bus_info);