@@ -1638,6 +1638,11 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error *
"on", false);
}
+ if (machine_class->smp_props.topo_tree_supported &&
+ !machine_create_topo_tree(machine, errp)) {
+ return;
+ }
+
accel_init_interfaces(ACCEL_GET_CLASS(machine->accelerator));
machine_class->init(machine);
phase_advance(PHASE_MACHINE_INITIALIZED);
@@ -12,8 +12,12 @@
#include "qemu/osdep.h"
#include "hw/boards.h"
+#include "hw/cpu/core.h"
#include "hw/cpu/cpu-slot.h"
#include "hw/cpu/cpu-topology.h"
+#include "hw/cpu/die.h"
+#include "hw/cpu/module.h"
+#include "hw/cpu/socket.h"
#include "hw/qdev-core.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
@@ -172,3 +176,152 @@ void machine_plug_cpu_slot(MachineState *ms)
qbus_set_hotplug_handler(BUS(&slot->bus), OBJECT(ms));
}
}
+
+static int get_smp_info_by_level(const CpuTopology *smp_info,
+ CpuTopologyLevel child_level)
+{
+ switch (child_level) {
+ case CPU_TOPOLOGY_LEVEL_THREAD:
+ return smp_info->threads;
+ case CPU_TOPOLOGY_LEVEL_CORE:
+ return smp_info->cores;
+ case CPU_TOPOLOGY_LEVEL_MODULE:
+ return smp_info->modules;
+ case CPU_TOPOLOGY_LEVEL_DIE:
+ return smp_info->dies;
+ case CPU_TOPOLOGY_LEVEL_SOCKET:
+ return smp_info->sockets;
+ default:
+ /* TODO: Add support for other levels. */
+ g_assert_not_reached();
+ }
+
+ return 0;
+}
+
+static const char *get_topo_typename_by_level(CpuTopologyLevel level)
+{
+ switch (level) {
+ case CPU_TOPOLOGY_LEVEL_CORE:
+ return TYPE_CPU_CORE;
+ case CPU_TOPOLOGY_LEVEL_MODULE:
+ return TYPE_CPU_MODULE;
+ case CPU_TOPOLOGY_LEVEL_DIE:
+ return TYPE_CPU_DIE;
+ case CPU_TOPOLOGY_LEVEL_SOCKET:
+ return TYPE_CPU_SOCKET;
+ default:
+ /* TODO: Add support for other levels. */
+ g_assert_not_reached();
+ }
+
+ return NULL;
+}
+
+typedef struct SMPBuildCbData {
+ DECLARE_BITMAP(create_levels, CPU_TOPOLOGY_LEVEL__MAX);
+ const CpuTopology *smp_info;
+ CPUTopoStat *stat;
+ Error **errp;
+} SMPBuildCbData;
+
+static int create_smp_topo_children(DeviceState *dev, void *opaque)
+{
+ Object *parent = OBJECT(dev);
+ CpuTopologyLevel child_level;
+ SMPBuildCbData *cb = opaque;
+ CPUTopoState *topo = NULL;
+ BusState *qbus;
+ CPUBusState *cbus;
+ Error **errp = cb->errp;
+ int max_children;
+
+ if (object_dynamic_cast(parent, TYPE_CPU_TOPO)) {
+ topo = CPU_TOPO(parent);
+ CpuTopologyLevel parent_level;
+
+ parent_level = GET_CPU_TOPO_LEVEL(topo);
+ child_level = find_last_bit(cb->create_levels, parent_level);
+
+ if (child_level == parent_level) {
+ return TOPO_FOREACH_CONTINUE;
+ }
+
+ cbus = topo->bus;
+ } else if (object_dynamic_cast(parent, TYPE_CPU_SLOT)) {
+ child_level = find_last_bit(cb->create_levels, CPU_TOPOLOGY_LEVEL__MAX);
+ cbus = &CPU_SLOT(parent)->bus;
+ } else {
+ return TOPO_FOREACH_ERR;
+ }
+
+ qbus = BUS(cbus);
+ max_children = get_smp_info_by_level(cb->smp_info, child_level);
+ for (int i = 0; i < max_children; i++) {
+ DeviceState *child;
+
+ child = qdev_new(get_topo_typename_by_level(child_level));
+
+ /*
+ * Bus inserts child device at head (QTAILQ_INSERT_HEAD_RCU), This
+ * could result in the device IDs in the created topology having a
+ * zig-zag arrangement.
+ *
+ * TODO: Remove obstacles preventing the use of QTAILQ_INSERT_HEAD_RCU
+ * for bus to insert kid device.
+ */
+ child->id = g_strdup_printf("%s[%d]",
+ CpuTopologyLevel_str(child_level),
+ cb->stat->entries[child_level].total_instances);
+
+ if (!qdev_realize_and_unref(child, qbus, errp)) {
+ return TOPO_FOREACH_ERR;
+ }
+ }
+
+ return TOPO_FOREACH_CONTINUE;
+}
+
+bool machine_create_topo_tree(MachineState *ms, Error **errp)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ CPUSlot *slot = ms->topo;
+ CpuTopologyLevel level;
+ SMPBuildCbData cb;
+
+ if (!slot) {
+ error_setg(errp, "Invalid machine: "
+ "the cpu-slot of machine is not initialized.");
+ return false;
+ }
+
+ /*
+ * Don't support full topology tree.
+ * Just use slot to collect topology device.
+ */
+ if (!mc->smp_props.arch_id_topo_level) {
+ return true;
+ }
+
+ bitmap_copy(cb.create_levels, slot->supported_levels,
+ CPU_TOPOLOGY_LEVEL__MAX);
+ cb.smp_info = &ms->smp;
+ cb.stat = &slot->stat;
+ cb.errp = errp;
+
+ /*
+ * Topology objects at arch_id_topo_level and lower levels will be
+ * created by MachineClass.possible_cpu_arch_ids().
+ */
+ FOR_EACH_SET_BIT(level, slot->supported_levels,
+ mc->smp_props.arch_id_topo_level + 1) {
+ clear_bit(level, cb.create_levels);
+ }
+
+ if (qdev_walk_children(DEVICE(slot), create_smp_topo_children,
+ NULL, NULL, NULL, &cb) < 0) {
+ return false;
+ }
+
+ return true;
+}
@@ -155,6 +155,7 @@ typedef struct {
* supported by the machine
* @topo_tree_supported - whether QOM topology tree is supported by the
* machine
+ * @arch_id_topo_level - topology granularity for possible_cpus[]
*/
typedef struct {
bool prefer_sockets;
@@ -166,6 +167,7 @@ typedef struct {
bool modules_supported;
bool cache_supported[CACHE_LEVEL_AND_TYPE__MAX];
bool topo_tree_supported;
+ CpuTopologyLevel arch_id_topo_level;
} SMPCompatProps;
/**
@@ -69,6 +69,11 @@ struct CPUSlot {
DeviceListener listener;
};
+#define TOPO_FOREACH_END 1
+#define TOPO_FOREACH_CONTINUE 0
+#define TOPO_FOREACH_ERR -1
+
void machine_plug_cpu_slot(MachineState *ms);
+bool machine_create_topo_tree(MachineState *ms, Error **errp);
#endif /* CPU_SLOT_H */
@@ -631,4 +631,9 @@ static inline uint64_t half_unshuffle64(uint64_t x)
return x;
}
+#define FOR_EACH_SET_BIT(bit, addr, size) \
+ for ((bit) = find_first_bit((addr), (size)); \
+ (bit) < (size); \
+ (bit) = find_next_bit((addr), (size), (bit) + 1))
+
#endif
For architectures supports QOM topology (indicated by the MachineClass. topo_tree_supported field), implement smp QOM topology tree from MachineState.smp. The topology tree is created before MachineClass.init(), where arch will initialize CPUs or cores, corresponding to the MachineState.possible_cpus[]. To avoid conflicts with CPU/core generation in the arch machine, create_smp_topo_children() will only create topology levels which are higher than the granularity of possible_cpus[]. The remaining topology parts will be completed by the arch machine during machine init(). There's a new field, arch_id_topo_level, to indicate the granularity of possible_cpus[]. While this field is set, CPU slot can create the topology tree level by level. Without this field, any topology device will be collect at the CPU bus of the CPU slot and will not be organized into a tree structure. Signed-off-by: Zhao Liu <zhao1.liu@intel.com> --- hw/core/machine.c | 5 ++ hw/cpu/cpu-slot.c | 153 ++++++++++++++++++++++++++++++++++++++ include/hw/boards.h | 2 + include/hw/cpu/cpu-slot.h | 5 ++ include/qemu/bitops.h | 5 ++ 5 files changed, 170 insertions(+)