@@ -143,6 +143,58 @@ bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp)
return true;
}
+/*
+ * Set the QOM parent and parent bus of an object child. If the device
+ * state associated with the child has an id, use it as QOM id.
+ * Otherwise use default_id as QOM id.
+ *
+ * This helper does both operations at the same time because setting
+ * a new QOM child will erase the bus parent of the device. This happens
+ * because object_unparent() will call object_property_del_child(),
+ * which in turn calls the property release callback prop->release if
+ * it's defined. In our case this callback is set to
+ * object_finalize_child_property(), which was assigned during the
+ * first object_property_add_child() call. This callback will end up
+ * calling device_unparent(), and this function removes the device
+ * from its parent bus.
+ *
+ * The QOM and parent bus to be set aren't necessarily related, so
+ * let's receive both as arguments.
+ */
+bool qdev_set_parent(DeviceState *dev, BusState *bus, Object *parent,
+ char *default_id, Error **errp)
+{
+ Object *child = OBJECT(dev);
+ ObjectProperty *prop;
+
+ if (!dev->id && !default_id) {
+ error_setg(errp, "unknown device id");
+ return false;
+ }
+
+ if (child->parent == parent) {
+ return true;
+ }
+
+ object_ref(child);
+ object_unparent(child);
+ prop = object_property_add_child(parent,
+ dev->id ? dev->id : default_id,
+ child);
+ object_unref(child);
+
+ if (!prop) {
+ error_setg(errp, "couldn't change parent");
+ return false;
+ }
+
+ if (!qdev_set_parent_bus(dev, bus, errp)) {
+ return false;
+ }
+
+ return true;
+}
+
DeviceState *qdev_new(const char *name)
{
ObjectClass *oc = object_class_by_name(name);
@@ -19,49 +19,6 @@
#include "qom/object.h"
#include "sysemu/sysemu.h"
-
-/*
- * Set the QOM parent and parent bus of an object child. If the device
- * state associated with the child has an id, use it as QOM id.
- * Otherwise use object_typename[index] as QOM id.
- *
- * This helper does both operations at the same time because setting
- * a new QOM child will erase the bus parent of the device. This happens
- * because object_unparent() will call object_property_del_child(),
- * which in turn calls the property release callback prop->release if
- * it's defined. In our case this callback is set to
- * object_finalize_child_property(), which was assigned during the
- * first object_property_add_child() call. This callback will end up
- * calling device_unparent(), and this function removes the device
- * from its parent bus.
- *
- * The QOM and parent bus to be set aren´t necessarily related, so
- * let's receive both as arguments.
- */
-static bool pnv_parent_fixup(Object *parent, BusState *parent_bus,
- Object *child, int index,
- Error **errp)
-{
- g_autofree char *default_id =
- g_strdup_printf("%s[%d]", object_get_typename(child), index);
- const char *dev_id = DEVICE(child)->id;
-
- if (child->parent == parent) {
- return true;
- }
-
- object_ref(child);
- object_unparent(child);
- object_property_add_child(parent, dev_id ? dev_id : default_id, child);
- object_unref(child);
-
- if (!qdev_set_parent_bus(DEVICE(child), parent_bus, errp)) {
- return false;
- }
-
- return true;
-}
-
static Object *pnv_phb_user_get_parent(PnvChip *chip, PnvPHB *phb, Error **errp)
{
if (phb->version == 3) {
@@ -82,6 +39,7 @@ static bool pnv_phb_user_device_init(PnvPHB *phb, Error **errp)
PnvMachineState *pnv = PNV_MACHINE(qdev_get_machine());
PnvChip *chip = pnv_get_chip(pnv, phb->chip_id);
Object *parent = NULL;
+ g_autofree char *default_id = NULL;
if (!chip) {
error_setg(errp, "invalid chip id: %d", phb->chip_id);
@@ -98,8 +56,11 @@ static bool pnv_phb_user_device_init(PnvPHB *phb, Error **errp)
* correctly the device tree. pnv_xscom_dt() needs every
* PHB to be a child of the chip to build the DT correctly.
*/
- if (!pnv_parent_fixup(parent, qdev_get_parent_bus(DEVICE(chip)),
- OBJECT(phb), phb->phb_id, errp)) {
+ default_id = g_strdup_printf("%s[%d]",
+ object_get_typename(OBJECT(phb)),
+ phb->phb_id);
+ if (!qdev_set_parent(DEVICE(phb), qdev_get_parent_bus(DEVICE(chip)),
+ parent, default_id, errp)) {
return false;
}
@@ -246,6 +207,7 @@ static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
uint16_t device_id = 0;
Error *local_err = NULL;
int chip_id, index;
+ g_autofree char *default_id = NULL;
/*
* 'index' will be used both as a PCIE slot value and to calculate
@@ -273,8 +235,11 @@ static void pnv_phb_root_port_realize(DeviceState *dev, Error **errp)
* parent bus. Change the QOM parent to be the same as the
* parent bus it's already assigned to.
*/
- if (!pnv_parent_fixup(OBJECT(bus), BUS(bus), OBJECT(dev),
- index, errp)) {
+ default_id = g_strdup_printf("%s[%d]",
+ object_get_typename(OBJECT(dev)),
+ index);
+ if (!qdev_set_parent(dev, BUS(bus), OBJECT(bus),
+ default_id, errp)) {
return;
}
@@ -1011,6 +1011,9 @@ char *qdev_get_human_name(DeviceState *dev);
/* FIXME: make this a link<> */
bool qdev_set_parent_bus(DeviceState *dev, BusState *bus, Error **errp);
+bool qdev_set_parent(DeviceState *dev, BusState *bus, Object *parent,
+ char *default_id, Error **errp);
+
extern bool qdev_hot_removed;
char *qdev_get_dev_path(DeviceState *dev);
User created devices may need to adjust their default object parent or parent bus. User created devices are QOM parented to one of the peripheral containers ("/peripheral" or "/peripheral-anon") in qdev_set_id() by default. Sometimes, it is necessary to reparent a device to another object to express the more accurate child<> relationship, as in the cases of the PnvPHBRootPort device or subsequent topology devices. The current pnv_phb_user_get_parent() implements such reparenting logic. To allow it to be used by topology devices as well, transform it into a generic qdev interface with custom device id ("default_id" parameter). And add the code to handle the failure of object_property_add_child(). Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- hw/core/qdev.c | 52 +++++++++++++++++++++++++++++++++++++ hw/pci-host/pnv_phb.c | 59 +++++++++--------------------------------- include/hw/qdev-core.h | 3 +++ 3 files changed, 67 insertions(+), 47 deletions(-)