Currently, cpu and core is located by topology IDs when plugging. On a topology tree, each topology device will has a CPU bus. Once cpu and core specify the bus_type, it's necessary to find accurate buses for them based on topology IDs (if bus=* is not set in -device). Therefore, we need a way to use traditional topology IDs for locating specific bus in the topology tree. This is the bus-finder interface. With bus-finder, qdev-monitor can locate the bus based on device properties when "bus=*" is not specified. Signed-off-by: Zhao Liu <zhao1.liu@xxxxxxxxx> --- MAINTAINERS | 2 ++ include/monitor/bus-finder.h | 41 ++++++++++++++++++++++++++++++++ system/bus-finder.c | 46 ++++++++++++++++++++++++++++++++++++ system/meson.build | 1 + system/qdev-monitor.c | 41 ++++++++++++++++++++++++++++---- 5 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 include/monitor/bus-finder.h create mode 100644 system/bus-finder.c diff --git a/MAINTAINERS b/MAINTAINERS index 03c1a13de074..4608c3c6db8c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3281,12 +3281,14 @@ F: hw/core/qdev* F: hw/core/bus.c F: hw/core/sysbus.c F: include/hw/qdev* +F: include/monitor/bus-finder.h F: include/monitor/qdev.h F: include/qom/ F: qapi/qom.json F: qapi/qdev.json F: scripts/coccinelle/qom-parent-type.cocci F: scripts/qom-cast-macro-clean-cocci-gen.py +F: system/bus-finder.c F: system/qdev-monitor.c F: stubs/qdev.c F: qom/ diff --git a/include/monitor/bus-finder.h b/include/monitor/bus-finder.h new file mode 100644 index 000000000000..56f1e4791b66 --- /dev/null +++ b/include/monitor/bus-finder.h @@ -0,0 +1,41 @@ +/* + * Bus finder interface header + * + * Copyright (C) 2024 Intel Corporation. + * + * Author: Zhao Liu <zhao1.liu@xxxxxxxxx> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#ifndef BUS_FINDER_H +#define BUS_FINDER_H + +#include "hw/qdev-core.h" +#include "qom/object.h" + +#define TYPE_BUS_FINDER "bus-finder" + +typedef struct BusFinderClass BusFinderClass; +DECLARE_CLASS_CHECKERS(BusFinderClass, BUS_FINDER, TYPE_BUS_FINDER) +#define BUS_FINDER(obj) INTERFACE_CHECK(BusFinder, (obj), TYPE_BUS_FINDER) + +typedef struct BusFinder BusFinder; + +/** + * BusFinderClass: + * @find_bus: Method to find bus. + */ +struct BusFinderClass { + /* <private> */ + InterfaceClass parent_class; + + /* <public> */ + BusState *(*find_bus)(DeviceState *dev); +}; + +bool is_bus_finder_type(DeviceClass *dc); +BusState *bus_finder_select_bus(DeviceState *dev); + +#endif /* BUS_FINDER_H */ diff --git a/system/bus-finder.c b/system/bus-finder.c new file mode 100644 index 000000000000..097291a96bf3 --- /dev/null +++ b/system/bus-finder.c @@ -0,0 +1,46 @@ +/* + * Bus finder interface + * + * Copyright (C) 2024 Intel Corporation. + * + * Author: Zhao Liu <zhao1.liu@xxxxxxxxx> + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * later. See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" + +#include "hw/qdev-core.h" +#include "monitor/bus-finder.h" +#include "qom/object.h" + +bool is_bus_finder_type(DeviceClass *dc) +{ + return !!object_class_dynamic_cast(OBJECT_CLASS(dc), TYPE_BUS_FINDER); +} + +BusState *bus_finder_select_bus(DeviceState *dev) +{ + BusFinder *bf = BUS_FINDER(dev); + BusFinderClass *bfc = BUS_FINDER_GET_CLASS(bf); + + if (bfc->find_bus) { + return bfc->find_bus(dev); + } + + return NULL; +} + +static const TypeInfo bus_finder_interface_info = { + .name = TYPE_BUS_FINDER, + .parent = TYPE_INTERFACE, + .class_size = sizeof(BusFinderClass), +}; + +static void bus_finder_register_types(void) +{ + type_register_static(&bus_finder_interface_info); +} + +type_init(bus_finder_register_types) diff --git a/system/meson.build b/system/meson.build index a296270cb005..090716b81abd 100644 --- a/system/meson.build +++ b/system/meson.build @@ -9,6 +9,7 @@ specific_ss.add(when: 'CONFIG_SYSTEM_ONLY', if_true: [files( system_ss.add(files( 'balloon.c', 'bootdevice.c', + 'bus-finder.c', 'cpus.c', 'cpu-throttle.c', 'cpu-timers.c', diff --git a/system/qdev-monitor.c b/system/qdev-monitor.c index 44994ea0e160..457dfd05115e 100644 --- a/system/qdev-monitor.c +++ b/system/qdev-monitor.c @@ -19,6 +19,7 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" +#include "monitor/bus-finder.h" #include "monitor/hmp.h" #include "monitor/monitor.h" #include "monitor/qdev.h" @@ -589,6 +590,16 @@ static BusState *qbus_find(const char *path, Error **errp) return bus; } +static inline bool qdev_post_find_bus(DeviceClass *dc) +{ + return is_bus_finder_type(dc); +} + +static inline BusState *qdev_find_bus_post_device(DeviceState *dev) +{ + return bus_finder_select_bus(dev); +} + /* Takes ownership of @id, will be freed when deleting the device */ const char *qdev_set_id(DeviceState *dev, char *id, Error **errp) { @@ -630,6 +641,7 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, char *id; DeviceState *dev = NULL; BusState *bus = NULL; + bool post_bus = false; driver = qdict_get_try_str(opts, "driver"); if (!driver) { @@ -656,11 +668,15 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, return NULL; } } else if (dc->bus_type != NULL) { - bus = qbus_find_recursive(sysbus_get_default(), NULL, dc->bus_type); - if (!bus || qbus_is_full(bus)) { - error_setg(errp, "No '%s' bus found for device '%s'", - dc->bus_type, driver); - return NULL; + if (qdev_post_find_bus(dc)) { + post_bus = true; /* Wait for bus-finder to arbitrate. */ + } else { + bus = qbus_find_recursive(sysbus_get_default(), NULL, dc->bus_type); + if (!bus || qbus_is_full(bus)) { + error_setg(errp, "No '%s' bus found for device '%s'", + dc->bus_type, driver); + return NULL; + } } } @@ -722,6 +738,21 @@ DeviceState *qdev_device_add_from_qdict(const QDict *opts, goto err_del_dev; } + if (post_bus) { + bus = qdev_find_bus_post_device(dev); + if (!bus) { + error_setg(errp, "No proper '%s' bus found for device '%s'", + dc->bus_type, driver); + goto err_del_dev; + } + + if (phase_check(PHASE_MACHINE_READY) && !qbus_is_hotpluggable(bus)) { + error_setg(errp, "Bus '%s' does not support hotplugging", + bus->name); + goto err_del_dev; + } + } + if (!qdev_realize(dev, bus, errp)) { goto err_del_dev; } -- 2.34.1