Perhaps I'm slow on the uptake today... We have
typedef struct XHCIPciState { /*< private >*/ PCIDevice parent_obj; /*< public >*/ (1) XHCIState xhci; OnOffAuto msi; OnOffAuto msix; } XHCIPciState; This is a PCI device that contains a (bus-less) TYPE_XHCI device, at (1). static void xhci_instance_init(Object *obj) { XHCIPciState *s = XHCI_PCI(obj); /* * QEMU_PCI_CAP_EXPRESS initialization does not depend on QEMU command * line, therefore, no need to wait to realize like other devices */ PCI_DEVICE(obj)->cap_present |= QEMU_PCI_CAP_EXPRESS; (2) object_initialize_child(obj, "xhci-core", &s->xhci, TYPE_XHCI); qdev_alias_all_properties(DEVICE(&s->xhci), obj); } The .instance_init() method initializes the child as it should, at (2). static void usb_xhci_pci_realize(struct PCIDevice *dev, Error **errp) { int ret; Error *err = NULL; XHCIPciState *s = XHCI_PCI(dev); [a few dev->config[] modifications...] (1) object_property_set_link(OBJECT(&s->xhci), "host", OBJECT(s), NULL); s->xhci.intr_update = xhci_pci_intr_update; s->xhci.intr_raise = xhci_pci_intr_raise; (2) object_property_set_bool(OBJECT(&s->xhci), "realized", true, &err); if (err) { error_propagate(errp, err); return; } The .realize() method realizes the child at (1). It should use qdev_realize() like we do everywhere else, since commit ce189ab230 "qdev: Convert bus-less devices to qdev_realize() with Coccinelle". It sets a link property from the child back to the parent at (2). Why do we need a link? Each QOM Object contains a pointer to its parent, doesn't it? Same for xhci_sysbus_realize().