qdev: Start disentangling bus from device

Move bus type and related APIs to a separate file bus.c.
This is a first step in breaking up qdev.c into more manageable chunks.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
[AF: Rebased onto osdep.h]
Signed-off-by: Andreas Färber <afaerber@suse.de>
[PMM: added bus.o to link line for test-qdev-global-props]
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Andreas Färber 2015-07-13 19:35:41 +02:00 committed by Peter Maydell
parent c88c67e58b
commit a62c89117f
4 changed files with 253 additions and 222 deletions

View File

@ -1,5 +1,6 @@
# core qdev-related obj files, also used by *-user: # core qdev-related obj files, also used by *-user:
common-obj-y += qdev.o qdev-properties.o common-obj-y += qdev.o qdev-properties.o
common-obj-y += bus.o
common-obj-y += fw-path-provider.o common-obj-y += fw-path-provider.o
# irq.o needed for qdev GPIO handling: # irq.o needed for qdev GPIO handling:
common-obj-y += irq.o common-obj-y += irq.o

251
hw/core/bus.c Normal file
View File

@ -0,0 +1,251 @@
/*
* Dynamic device configuration and creation -- buses.
*
* Copyright (c) 2009 CodeSourcery
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu-common.h"
#include "hw/qdev.h"
#include "qapi/error.h"
static void qbus_set_hotplug_handler_internal(BusState *bus, Object *handler,
Error **errp)
{
object_property_set_link(OBJECT(bus), OBJECT(handler),
QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
}
void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler, Error **errp)
{
qbus_set_hotplug_handler_internal(bus, OBJECT(handler), errp);
}
void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp)
{
qbus_set_hotplug_handler_internal(bus, OBJECT(bus), errp);
}
int qbus_walk_children(BusState *bus,
qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
void *opaque)
{
BusChild *kid;
int err;
if (pre_busfn) {
err = pre_busfn(bus, opaque);
if (err) {
return err;
}
}
QTAILQ_FOREACH(kid, &bus->children, sibling) {
err = qdev_walk_children(kid->child,
pre_devfn, pre_busfn,
post_devfn, post_busfn, opaque);
if (err < 0) {
return err;
}
}
if (post_busfn) {
err = post_busfn(bus, opaque);
if (err) {
return err;
}
}
return 0;
}
static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
{
const char *typename = object_get_typename(OBJECT(bus));
BusClass *bc;
char *buf;
int i, len, bus_id;
bus->parent = parent;
if (name) {
bus->name = g_strdup(name);
} else if (bus->parent && bus->parent->id) {
/* parent device has id -> use it plus parent-bus-id for bus name */
bus_id = bus->parent->num_child_bus;
len = strlen(bus->parent->id) + 16;
buf = g_malloc(len);
snprintf(buf, len, "%s.%d", bus->parent->id, bus_id);
bus->name = buf;
} else {
/* no id -> use lowercase bus type plus global bus-id for bus name */
bc = BUS_GET_CLASS(bus);
bus_id = bc->automatic_ids++;
len = strlen(typename) + 16;
buf = g_malloc(len);
len = snprintf(buf, len, "%s.%d", typename, bus_id);
for (i = 0; i < len; i++) {
buf[i] = qemu_tolower(buf[i]);
}
bus->name = buf;
}
if (bus->parent) {
QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling);
bus->parent->num_child_bus++;
object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL);
object_unref(OBJECT(bus));
} else if (bus != sysbus_get_default()) {
/* TODO: once all bus devices are qdevified,
only reset handler for main_system_bus should be registered here. */
qemu_register_reset(qbus_reset_all_fn, bus);
}
}
static void bus_unparent(Object *obj)
{
BusState *bus = BUS(obj);
BusChild *kid;
while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
DeviceState *dev = kid->child;
object_unparent(OBJECT(dev));
}
if (bus->parent) {
QLIST_REMOVE(bus, sibling);
bus->parent->num_child_bus--;
bus->parent = NULL;
} else {
assert(bus != sysbus_get_default()); /* main_system_bus is never freed */
qemu_unregister_reset(qbus_reset_all_fn, bus);
}
}
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);
}
BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
{
BusState *bus;
bus = BUS(object_new(typename));
qbus_realize(bus, parent, name);
return bus;
}
static bool bus_get_realized(Object *obj, Error **errp)
{
BusState *bus = BUS(obj);
return bus->realized;
}
static void bus_set_realized(Object *obj, bool value, Error **errp)
{
BusState *bus = BUS(obj);
BusClass *bc = BUS_GET_CLASS(bus);
BusChild *kid;
Error *local_err = NULL;
if (value && !bus->realized) {
if (bc->realize) {
bc->realize(bus, &local_err);
}
/* TODO: recursive realization */
} else if (!value && bus->realized) {
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
object_property_set_bool(OBJECT(dev), false, "realized",
&local_err);
if (local_err != NULL) {
break;
}
}
if (bc->unrealize && local_err == NULL) {
bc->unrealize(bus, &local_err);
}
}
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
bus->realized = value;
}
static void qbus_initfn(Object *obj)
{
BusState *bus = BUS(obj);
QTAILQ_INIT(&bus->children);
object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY,
TYPE_HOTPLUG_HANDLER,
(Object **)&bus->hotplug_handler,
object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
NULL);
object_property_add_bool(obj, "realized",
bus_get_realized, bus_set_realized, NULL);
}
static char *default_bus_get_fw_dev_path(DeviceState *dev)
{
return g_strdup(object_get_typename(OBJECT(dev)));
}
static void bus_class_init(ObjectClass *class, void *data)
{
BusClass *bc = BUS_CLASS(class);
class->unparent = bus_unparent;
bc->get_fw_dev_path = default_bus_get_fw_dev_path;
}
static void qbus_finalize(Object *obj)
{
BusState *bus = BUS(obj);
g_free((char *)bus->name);
}
static const TypeInfo bus_info = {
.name = TYPE_BUS,
.parent = TYPE_OBJECT,
.instance_size = sizeof(BusState),
.abstract = true,
.class_size = sizeof(BusClass),
.instance_init = qbus_initfn,
.instance_finalize = qbus_finalize,
.class_init = bus_class_init,
};
static void bus_register_types(void)
{
type_register_static(&bus_info);
}
type_init(bus_register_types)

View File

@ -109,24 +109,6 @@ void qdev_set_parent_bus(DeviceState *dev, BusState *bus)
bus_add_child(bus, dev); bus_add_child(bus, dev);
} }
static void qbus_set_hotplug_handler_internal(BusState *bus, Object *handler,
Error **errp)
{
object_property_set_link(OBJECT(bus), OBJECT(handler),
QDEV_HOTPLUG_HANDLER_PROPERTY, errp);
}
void qbus_set_hotplug_handler(BusState *bus, DeviceState *handler, Error **errp)
{
qbus_set_hotplug_handler_internal(bus, OBJECT(handler), errp);
}
void qbus_set_bus_hotplug_handler(BusState *bus, Error **errp)
{
qbus_set_hotplug_handler_internal(bus, OBJECT(bus), errp);
}
/* Create a new device. This only initializes the device state /* Create a new device. This only initializes the device state
structure and allows properties to be set. The device still needs structure and allows properties to be set. The device still needs
to be realized. See qdev-core.h. */ to be realized. See qdev-core.h. */
@ -595,40 +577,6 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
return NULL; return NULL;
} }
int qbus_walk_children(BusState *bus,
qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
void *opaque)
{
BusChild *kid;
int err;
if (pre_busfn) {
err = pre_busfn(bus, opaque);
if (err) {
return err;
}
}
QTAILQ_FOREACH(kid, &bus->children, sibling) {
err = qdev_walk_children(kid->child,
pre_devfn, pre_busfn,
post_devfn, post_busfn, opaque);
if (err < 0) {
return err;
}
}
if (post_busfn) {
err = post_busfn(bus, opaque);
if (err) {
return err;
}
}
return 0;
}
int qdev_walk_children(DeviceState *dev, int qdev_walk_children(DeviceState *dev,
qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn, qdev_walkerfn *pre_devfn, qbus_walkerfn *pre_busfn,
qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn, qdev_walkerfn *post_devfn, qbus_walkerfn *post_busfn,
@ -685,129 +633,6 @@ DeviceState *qdev_find_recursive(BusState *bus, const char *id)
return NULL; return NULL;
} }
static void qbus_realize(BusState *bus, DeviceState *parent, const char *name)
{
const char *typename = object_get_typename(OBJECT(bus));
BusClass *bc;
char *buf;
int i, len, bus_id;
bus->parent = parent;
if (name) {
bus->name = g_strdup(name);
} else if (bus->parent && bus->parent->id) {
/* parent device has id -> use it plus parent-bus-id for bus name */
bus_id = bus->parent->num_child_bus;
len = strlen(bus->parent->id) + 16;
buf = g_malloc(len);
snprintf(buf, len, "%s.%d", bus->parent->id, bus_id);
bus->name = buf;
} else {
/* no id -> use lowercase bus type plus global bus-id for bus name */
bc = BUS_GET_CLASS(bus);
bus_id = bc->automatic_ids++;
len = strlen(typename) + 16;
buf = g_malloc(len);
len = snprintf(buf, len, "%s.%d", typename, bus_id);
for (i = 0; i < len; i++) {
buf[i] = qemu_tolower(buf[i]);
}
bus->name = buf;
}
if (bus->parent) {
QLIST_INSERT_HEAD(&bus->parent->child_bus, bus, sibling);
bus->parent->num_child_bus++;
object_property_add_child(OBJECT(bus->parent), bus->name, OBJECT(bus), NULL);
object_unref(OBJECT(bus));
} else if (bus != sysbus_get_default()) {
/* TODO: once all bus devices are qdevified,
only reset handler for main_system_bus should be registered here. */
qemu_register_reset(qbus_reset_all_fn, bus);
}
}
static void bus_unparent(Object *obj)
{
BusState *bus = BUS(obj);
BusChild *kid;
while ((kid = QTAILQ_FIRST(&bus->children)) != NULL) {
DeviceState *dev = kid->child;
object_unparent(OBJECT(dev));
}
if (bus->parent) {
QLIST_REMOVE(bus, sibling);
bus->parent->num_child_bus--;
bus->parent = NULL;
} else {
assert(bus != sysbus_get_default()); /* main_system_bus is never freed */
qemu_unregister_reset(qbus_reset_all_fn, bus);
}
}
static bool bus_get_realized(Object *obj, Error **errp)
{
BusState *bus = BUS(obj);
return bus->realized;
}
static void bus_set_realized(Object *obj, bool value, Error **errp)
{
BusState *bus = BUS(obj);
BusClass *bc = BUS_GET_CLASS(bus);
BusChild *kid;
Error *local_err = NULL;
if (value && !bus->realized) {
if (bc->realize) {
bc->realize(bus, &local_err);
}
/* TODO: recursive realization */
} else if (!value && bus->realized) {
QTAILQ_FOREACH(kid, &bus->children, sibling) {
DeviceState *dev = kid->child;
object_property_set_bool(OBJECT(dev), false, "realized",
&local_err);
if (local_err != NULL) {
break;
}
}
if (bc->unrealize && local_err == NULL) {
bc->unrealize(bus, &local_err);
}
}
if (local_err != NULL) {
error_propagate(errp, local_err);
return;
}
bus->realized = value;
}
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);
}
BusState *qbus_create(const char *typename, DeviceState *parent, const char *name)
{
BusState *bus;
bus = BUS(object_new(typename));
qbus_realize(bus, parent, name);
return bus;
}
static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev) static char *bus_get_fw_dev_path(BusState *bus, DeviceState *dev)
{ {
BusClass *bc = BUS_GET_CLASS(bus); BusClass *bc = BUS_GET_CLASS(bus);
@ -1315,55 +1140,8 @@ static const TypeInfo device_type_info = {
.class_size = sizeof(DeviceClass), .class_size = sizeof(DeviceClass),
}; };
static void qbus_initfn(Object *obj)
{
BusState *bus = BUS(obj);
QTAILQ_INIT(&bus->children);
object_property_add_link(obj, QDEV_HOTPLUG_HANDLER_PROPERTY,
TYPE_HOTPLUG_HANDLER,
(Object **)&bus->hotplug_handler,
object_property_allow_set_link,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
NULL);
object_property_add_bool(obj, "realized",
bus_get_realized, bus_set_realized, NULL);
}
static char *default_bus_get_fw_dev_path(DeviceState *dev)
{
return g_strdup(object_get_typename(OBJECT(dev)));
}
static void bus_class_init(ObjectClass *class, void *data)
{
BusClass *bc = BUS_CLASS(class);
class->unparent = bus_unparent;
bc->get_fw_dev_path = default_bus_get_fw_dev_path;
}
static void qbus_finalize(Object *obj)
{
BusState *bus = BUS(obj);
g_free((char *)bus->name);
}
static const TypeInfo bus_info = {
.name = TYPE_BUS,
.parent = TYPE_OBJECT,
.instance_size = sizeof(BusState),
.abstract = true,
.class_size = sizeof(BusClass),
.instance_init = qbus_initfn,
.instance_finalize = qbus_finalize,
.class_init = bus_class_init,
};
static void qdev_register_types(void) static void qdev_register_types(void)
{ {
type_register_static(&bus_info);
type_register_static(&device_type_info); type_register_static(&device_type_info);
} }

View File

@ -434,6 +434,7 @@ tests/test-rcu-list$(EXESUF): tests/test-rcu-list.o $(test-util-obj-y)
tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \ tests/test-qdev-global-props$(EXESUF): tests/test-qdev-global-props.o \
hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\ hw/core/qdev.o hw/core/qdev-properties.o hw/core/hotplug.o\
hw/core/bus.o \
hw/core/irq.o \ hw/core/irq.o \
hw/core/fw-path-provider.o \ hw/core/fw-path-provider.o \
$(test-qapi-obj-y) $(test-qapi-obj-y)