* [RFC v2 01/15] qdev: Add pointer to BusChild in DeviceState
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 02/15] qdev: Add the interface to reparent the device Zhao Liu
` (13 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
The device topology structures based on buses are unidirectional: the
parent device can access the child device through the BusChild within
the bus, but not vice versa.
For the CPU topology tree constructed on the device-bus, it is necessary
for the child device to be able to access the parent device via the
parent bus. To address this, introduce a pointer to the BusChild, named
bus_node.
This pointer also simplifies the logic of bus_remove_child(). Instead of
the parent bus needing to traverse the children list to locate the
corresponding BusChild, it can now directly find it using the bus_node
pointer.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
hw/core/qdev.c | 29 ++++++++++++++---------------
include/hw/qdev-core.h | 4 ++++
include/qemu/typedefs.h | 1 +
3 files changed, 19 insertions(+), 15 deletions(-)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index db36f54d914a..4429856eaddd 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -57,25 +57,23 @@ static void bus_free_bus_child(BusChild *kid)
static void bus_remove_child(BusState *bus, DeviceState *child)
{
- BusChild *kid;
-
- QTAILQ_FOREACH(kid, &bus->children, sibling) {
- if (kid->child == child) {
- char name[32];
+ BusChild *kid = child->bus_node;
+ char name[32];
- snprintf(name, sizeof(name), "child[%d]", kid->index);
- QTAILQ_REMOVE_RCU(&bus->children, kid, sibling);
+ if (!kid) {
+ return;
+ }
- bus->num_children--;
+ snprintf(name, sizeof(name), "child[%d]", kid->index);
+ QTAILQ_REMOVE_RCU(&bus->children, kid, sibling);
+ child->bus_node = NULL;
+ bus->num_children--;
- /* This gives back ownership of kid->child back to us. */
- object_property_del(OBJECT(bus), name);
+ /* This gives back ownership of kid->child back to us. */
+ object_property_del(OBJECT(bus), name);
- /* free the bus kid, when it is safe to do so*/
- call_rcu(kid, bus_free_bus_child, rcu);
- break;
- }
- }
+ /* free the bus kid, when it is safe to do so*/
+ call_rcu(kid, bus_free_bus_child, rcu);
}
static void bus_add_child(BusState *bus, DeviceState *child)
@@ -86,6 +84,7 @@ static void bus_add_child(BusState *bus, DeviceState *child)
bus->num_children++;
kid->index = bus->max_index++;
kid->child = child;
+ child->bus_node = kid;
object_ref(OBJECT(kid->child));
QTAILQ_INSERT_HEAD_RCU(&bus->children, kid, sibling);
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index aa97c34a4be7..85c7d462dfba 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -253,6 +253,10 @@ struct DeviceState {
* @parent_bus: bus this device belongs to
*/
BusState *parent_bus;
+ /**
+ * @bus_node: bus node inserted in parent bus
+ */
+ BusChild *bus_node;
/**
* @gpios: QLIST of named GPIOs the device provides.
*/
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 9d222dc37628..aef41c4e67ce 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -32,6 +32,7 @@ typedef struct BdrvDirtyBitmapIter BdrvDirtyBitmapIter;
typedef struct BlockBackend BlockBackend;
typedef struct BlockBackendRootState BlockBackendRootState;
typedef struct BlockDriverState BlockDriverState;
+typedef struct BusChild BusChild;
typedef struct BusClass BusClass;
typedef struct BusState BusState;
typedef struct Chardev Chardev;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 02/15] qdev: Add the interface to reparent the device
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
2024-09-19 1:55 ` [RFC v2 01/15] qdev: Add pointer to BusChild in DeviceState Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 03/15] hw/cpu: Introduce CPU topology device and CPU bus Zhao Liu
` (12 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
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(-)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index 4429856eaddd..ff073cbff56d 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -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);
diff --git a/hw/pci-host/pnv_phb.c b/hw/pci-host/pnv_phb.c
index d4c118d44362..a26e7b7aec5c 100644
--- a/hw/pci-host/pnv_phb.c
+++ b/hw/pci-host/pnv_phb.c
@@ -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;
}
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 85c7d462dfba..7cbc5fb97298 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -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);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 03/15] hw/cpu: Introduce CPU topology device and CPU bus
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
2024-09-19 1:55 ` [RFC v2 01/15] qdev: Add pointer to BusChild in DeviceState Zhao Liu
2024-09-19 1:55 ` [RFC v2 02/15] qdev: Add the interface to reparent the device Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 04/15] hw/cpu: Introduce CPU slot to manage CPU topology Zhao Liu
` (11 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
Hybrid (or heterogeneous) CPU topology needs to be expressed as
a topology tree, which requires to abstract all the CPU topology
level as the objects.
At present, QEMU already has the CPU device, core device and cluster
device (for TCG), so that it's natual to introduce more topology
related devices instead of abstractong native QEMU objects.
To make it easier to deal with topological relationships, introduce
the general and abstract CPU topology device, and also introduce the
CPU bus to connect such CPU topology devices.
With the underlying CPU topology device abstraction, all the CPU
topology levels could be derived from it as subclasses. Then the
specific devices, such as CPU, core, or future module/die/socket devices
etc, don't have to care about topology relationship, and the underlying
CPU topology abstraction and CPU bus will take care of everything and
build the topology tree.
Note, for the user created topology devices, they are specified the
default object parent (one of the peripheral containers: "/peripheral"
or "/peripheral-anon"). It's necessary to fixup their parent object
to correct topology parent, so that it can make their canonical path
in qtree match the actual topological hierarchies relationship. This
is done by cpu_topo_set_parent() when topology device realizes.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
MAINTAINERS | 2 +
hw/cpu/cpu-topology.c | 179 ++++++++++++++++++++++++++++++++++
hw/cpu/meson.build | 2 +
include/hw/cpu/cpu-topology.h | 68 +++++++++++++
include/qemu/typedefs.h | 2 +
stubs/hotplug-stubs.c | 5 +
6 files changed, 258 insertions(+)
create mode 100644 hw/cpu/cpu-topology.c
create mode 100644 include/hw/cpu/cpu-topology.h
diff --git a/MAINTAINERS b/MAINTAINERS
index ffacd60f4075..230267597b5f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1884,12 +1884,14 @@ F: hw/core/machine-smp.c
F: hw/core/null-machine.c
F: hw/core/numa.c
F: hw/cpu/cluster.c
+F: hw/cpu/cpu-topology.c
F: qapi/machine.json
F: qapi/machine-common.json
F: qapi/machine-target.json
F: include/hw/boards.h
F: include/hw/core/cpu.h
F: include/hw/cpu/cluster.h
+F: include/hw/cpu/cpu-topology.h
F: include/sysemu/numa.h
F: tests/functional/test_cpu_queries.py
F: tests/functional/test_empty_cpu_model.py
diff --git a/hw/cpu/cpu-topology.c b/hw/cpu/cpu-topology.c
new file mode 100644
index 000000000000..e68c06132e7d
--- /dev/null
+++ b/hw/cpu/cpu-topology.c
@@ -0,0 +1,179 @@
+/*
+ * General CPU topology device abstraction
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * 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/cpu/cpu-topology.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "qapi/error.h"
+
+/* Roll up until topology root to check. */
+static bool cpu_parent_check_topology(DeviceState *parent,
+ DeviceState *dev,
+ Error **errp)
+{
+ BusClass *bc;
+
+ if (!parent || !parent->parent_bus ||
+ object_dynamic_cast(OBJECT(parent->parent_bus), TYPE_CPU_BUS)) {
+ return true;
+ }
+
+ bc = BUS_GET_CLASS(parent->parent_bus);
+ if (bc->check_address) {
+ return bc->check_address(parent->parent_bus, dev, errp);
+ }
+
+ return true;
+}
+
+static bool cpu_bus_check_address(BusState *bus, DeviceState *dev,
+ Error **errp)
+{
+ CPUBusState *cbus = CPU_BUS(bus);
+
+ if (cbus->check_topology) {
+ return cbus->check_topology(CPU_BUS(bus), CPU_TOPO(dev), errp);
+ }
+
+ return cpu_parent_check_topology(bus->parent, dev, errp);
+}
+
+static void cpu_bus_class_init(ObjectClass *oc, void *data)
+{
+ BusClass *bc = BUS_CLASS(oc);
+
+ bc->check_address = cpu_bus_check_address;
+}
+
+static const TypeInfo cpu_bus_type_info = {
+ .name = TYPE_CPU_BUS,
+ .parent = TYPE_BUS,
+ .class_init = cpu_bus_class_init,
+ .instance_size = sizeof(CPUBusState),
+};
+
+static bool cpu_topo_set_parent(CPUTopoState *topo, Error **errp)
+{
+ DeviceState *dev = DEVICE(topo);
+ BusState *bus = dev->parent_bus;
+ CPUTopoState *parent_topo = NULL;
+ Object *parent;
+
+ if (!bus || !bus->parent) {
+ return true;
+ }
+
+ if (topo->parent) {
+ error_setg(errp, "cpu topo: %s already have the parent?",
+ object_get_typename(OBJECT(topo)));
+ return false;
+ }
+
+ parent = OBJECT(bus->parent);
+ if (object_dynamic_cast(parent, TYPE_CPU_TOPO)) {
+ parent_topo = CPU_TOPO(parent);
+
+ if (GET_CPU_TOPO_LEVEL(topo) >= GET_CPU_TOPO_LEVEL(parent_topo)) {
+ error_setg(errp, "cpu topo: current level (%s) should be "
+ "lower than parent (%s) level",
+ object_get_typename(OBJECT(topo)),
+ object_get_typename(parent));
+ return false;
+ }
+ }
+
+ if (dev->id) {
+ /*
+ * Reparent topology device to make child<> match topological
+ * relationship.
+ */
+ if (!qdev_set_parent(dev, bus, parent, NULL, errp)) {
+ return false;
+ }
+ }
+
+ topo->parent = parent_topo;
+ return true;
+}
+
+static void cpu_topo_realize(DeviceState *dev, Error **errp)
+{
+ CPUTopoState *topo = CPU_TOPO(dev);
+ CPUTopoClass *tc = CPU_TOPO_GET_CLASS(topo);
+ HotplugHandler *hotplug_handler;
+
+ if (tc->level == CPU_TOPOLOGY_LEVEL_INVALID) {
+ error_setg(errp, "cpu topo: no level specified type: %s",
+ object_get_typename(OBJECT(dev)));
+ return;
+ }
+
+ if (!cpu_topo_set_parent(topo, errp)) {
+ return;
+ }
+
+ topo->bus = CPU_BUS(qbus_new(TYPE_CPU_BUS, dev, dev->id));
+ hotplug_handler = qdev_get_bus_hotplug_handler(dev);
+ if (hotplug_handler) {
+ qbus_set_hotplug_handler(BUS(topo->bus), OBJECT(hotplug_handler));
+ }
+}
+
+static void cpu_topo_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+ CPUTopoClass *tc = CPU_TOPO_CLASS(oc);
+
+ set_bit(DEVICE_CATEGORY_CPU, dc->categories);
+ dc->realize = cpu_topo_realize;
+
+ /*
+ * If people doesn't want a topology tree, it's necessary to
+ * derive a child class and override this as NULL.
+ */
+ dc->bus_type = TYPE_CPU_BUS;
+
+ /*
+ * The general topo device is not hotpluggable by default.
+ * If any topo device needs hotplug support, this flag must be
+ * overridden.
+ */
+ dc->hotpluggable = false;
+
+ tc->level = CPU_TOPOLOGY_LEVEL_INVALID;
+}
+
+static const TypeInfo cpu_topo_type_info = {
+ .name = TYPE_CPU_TOPO,
+ .parent = TYPE_DEVICE,
+ .abstract = true,
+ .class_size = sizeof(CPUTopoClass),
+ .class_init = cpu_topo_class_init,
+ .instance_size = sizeof(CPUTopoState),
+};
+
+static void cpu_topo_register_types(void)
+{
+ type_register_static(&cpu_bus_type_info);
+ type_register_static(&cpu_topo_type_info);
+}
+
+type_init(cpu_topo_register_types)
+
+int cpu_topo_get_instances_num(CPUTopoState *topo)
+{
+ BusState *bus = DEVICE(topo)->parent_bus;
+
+ return bus ? bus->num_children : 1;
+}
diff --git a/hw/cpu/meson.build b/hw/cpu/meson.build
index 9d36bf8ae2c1..6c6546646608 100644
--- a/hw/cpu/meson.build
+++ b/hw/cpu/meson.build
@@ -1,3 +1,5 @@
+common_ss.add(files('cpu-topology.c'))
+
system_ss.add(files('core.c'))
system_ss.add(when: 'CONFIG_CPU_CLUSTER', if_true: files('cluster.c'))
diff --git a/include/hw/cpu/cpu-topology.h b/include/hw/cpu/cpu-topology.h
new file mode 100644
index 000000000000..7a447ad16ee7
--- /dev/null
+++ b/include/hw/cpu/cpu-topology.h
@@ -0,0 +1,68 @@
+/*
+ * General CPU topology device abstraction
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * 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 CPU_TOPO_H
+#define CPU_TOPO_H
+
+#include "hw/qdev-core.h"
+#include "qapi/qapi-types-machine-common.h"
+#include "qom/object.h"
+
+#define TYPE_CPU_BUS "cpu-bus"
+OBJECT_DECLARE_SIMPLE_TYPE(CPUBusState, CPU_BUS)
+
+/**
+ * CPUBusState:
+ * @check_topology: Method to check if @topo is supported by @cbus.
+ */
+struct CPUBusState {
+ /*< private >*/
+ BusState parent_obj;
+
+ /*< public >*/
+ bool (*check_topology)(CPUBusState *cbus, CPUTopoState *topo,
+ Error **errp);
+};
+
+#define TYPE_CPU_TOPO "cpu-topo"
+OBJECT_DECLARE_TYPE(CPUTopoState, CPUTopoClass, CPU_TOPO)
+
+/**
+ * CPUTopoClass:
+ * @level: Topology level for this CPUTopoClass.
+ */
+struct CPUTopoClass {
+ /*< private >*/
+ DeviceClass parent_class;
+
+ /*< public >*/
+ CpuTopologyLevel level;
+};
+
+/**
+ * CPUTopoState:
+ * @parent: Topology parent of this topology device.
+ * @bus: The CPU bus to add the children device.
+ */
+struct CPUTopoState {
+ /*< private >*/
+ DeviceState parent_obj;
+
+ /*< public >*/
+ struct CPUTopoState *parent;
+ CPUBusState *bus;
+};
+
+#define GET_CPU_TOPO_LEVEL(topo) (CPU_TOPO_GET_CLASS(topo)->level)
+
+int cpu_topo_get_instances_num(CPUTopoState *topo);
+
+#endif /* CPU_TOPO_H */
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index aef41c4e67ce..d62d8687403f 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -39,8 +39,10 @@ typedef struct Chardev Chardev;
typedef struct Clock Clock;
typedef struct ConfidentialGuestSupport ConfidentialGuestSupport;
typedef struct CPUArchState CPUArchState;
+typedef struct CPUBusState CPUBusState;
typedef struct CPUPluginState CPUPluginState;
typedef struct CPUState CPUState;
+typedef struct CPUTopoState CPUTopoState;
typedef struct DeviceState DeviceState;
typedef struct DirtyBitmapSnapshot DirtyBitmapSnapshot;
typedef struct DisasContextBase DisasContextBase;
diff --git a/stubs/hotplug-stubs.c b/stubs/hotplug-stubs.c
index 7aadaa29bd57..791fae079d6d 100644
--- a/stubs/hotplug-stubs.c
+++ b/stubs/hotplug-stubs.c
@@ -19,6 +19,11 @@ HotplugHandler *qdev_get_hotplug_handler(DeviceState *dev)
return NULL;
}
+HotplugHandler *qdev_get_bus_hotplug_handler(DeviceState *dev)
+{
+ return NULL;
+}
+
void hotplug_handler_pre_plug(HotplugHandler *plug_handler,
DeviceState *plugged_dev,
Error **errp)
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 04/15] hw/cpu: Introduce CPU slot to manage CPU topology
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (2 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 03/15] hw/cpu: Introduce CPU topology device and CPU bus Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 05/15] qdev: Add method in BusClass to customize device index Zhao Liu
` (10 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
When there's a CPU topology tree, original MachineState.smp (CpuTopology
structure) is not enough to dynamically monitor changes of the tree or
update topology information in time.
To address this, introduce the CPU slot, as the root of CPU topology
tree, which is used to update and maintain global topological statistics
by listening any changes of topology device (realize() and unrealize()).
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
MAINTAINERS | 2 +
hw/cpu/cpu-slot.c | 140 ++++++++++++++++++++++++++++++++++++++
hw/cpu/meson.build | 1 +
include/hw/cpu/cpu-slot.h | 72 ++++++++++++++++++++
4 files changed, 215 insertions(+)
create mode 100644 hw/cpu/cpu-slot.c
create mode 100644 include/hw/cpu/cpu-slot.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 230267597b5f..8e5b2cd91dca 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1884,6 +1884,7 @@ F: hw/core/machine-smp.c
F: hw/core/null-machine.c
F: hw/core/numa.c
F: hw/cpu/cluster.c
+F: hw/cpu/cpu-slot.c
F: hw/cpu/cpu-topology.c
F: qapi/machine.json
F: qapi/machine-common.json
@@ -1891,6 +1892,7 @@ F: qapi/machine-target.json
F: include/hw/boards.h
F: include/hw/core/cpu.h
F: include/hw/cpu/cluster.h
+F: include/hw/cpu/cpu-slot.h
F: include/hw/cpu/cpu-topology.h
F: include/sysemu/numa.h
F: tests/functional/test_cpu_queries.py
diff --git a/hw/cpu/cpu-slot.c b/hw/cpu/cpu-slot.c
new file mode 100644
index 000000000000..66ef8d9faa97
--- /dev/null
+++ b/hw/cpu/cpu-slot.c
@@ -0,0 +1,140 @@
+/*
+ * CPU slot abstraction - manage CPU topology
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * 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/boards.h"
+#include "hw/cpu/cpu-slot.h"
+#include "hw/cpu/cpu-topology.h"
+#include "hw/qdev-core.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "qapi/error.h"
+
+static void cpu_slot_add_topo_info(CPUSlot *slot, CPUTopoState *topo)
+{
+ CpuTopologyLevel level = GET_CPU_TOPO_LEVEL(topo);
+ CPUTopoStatEntry *entry;
+ int instances_num;
+
+ entry = &slot->stat.entries[level];
+ entry->total_instances++;
+
+ instances_num = cpu_topo_get_instances_num(topo);
+ if (instances_num > entry->max_instances) {
+ entry->max_instances = instances_num;
+ }
+
+ set_bit(level, slot->stat.curr_levels);
+
+ return;
+}
+
+static void cpu_slot_device_realize(DeviceListener *listener,
+ DeviceState *dev)
+{
+ CPUSlot *slot = container_of(listener, CPUSlot, listener);
+ CPUTopoState *topo;
+
+ if (!object_dynamic_cast(OBJECT(dev), TYPE_CPU_TOPO)) {
+ return;
+ }
+
+ topo = CPU_TOPO(dev);
+ cpu_slot_add_topo_info(slot, topo);
+}
+
+static void cpu_slot_del_topo_info(CPUSlot *slot, CPUTopoState *topo)
+{
+ CpuTopologyLevel level = GET_CPU_TOPO_LEVEL(topo);
+ CPUTopoStatEntry *entry;
+
+ entry = &slot->stat.entries[level];
+ entry->total_instances--;
+
+ return;
+}
+
+static void cpu_slot_device_unrealize(DeviceListener *listener,
+ DeviceState *dev)
+{
+ CPUSlot *slot = container_of(listener, CPUSlot, listener);
+ CPUTopoState *topo;
+
+ if (!object_dynamic_cast(OBJECT(dev), TYPE_CPU_TOPO)) {
+ return;
+ }
+
+ topo = CPU_TOPO(dev);
+ cpu_slot_del_topo_info(slot, topo);
+}
+
+DeviceListener cpu_slot_device_listener = {
+ .realize = cpu_slot_device_realize,
+ .unrealize = cpu_slot_device_unrealize,
+};
+
+static bool slot_bus_check_topology(CPUBusState *cbus,
+ CPUTopoState *topo,
+ Error **errp)
+{
+ CPUSlot *slot = CPU_SLOT(BUS(cbus)->parent);
+ CpuTopologyLevel level = GET_CPU_TOPO_LEVEL(topo);
+
+ if (!test_bit(level, slot->supported_levels)) {
+ error_setg(errp, "cpu topo: level %s is not supported",
+ CpuTopologyLevel_str(level));
+ return false;
+ }
+ return true;
+}
+
+static void cpu_slot_realize(DeviceState *dev, Error **errp)
+{
+ CPUSlot *slot = CPU_SLOT(dev);
+
+ slot->listener = cpu_slot_device_listener;
+ device_listener_register(&slot->listener);
+
+ qbus_init(&slot->bus, sizeof(CPUBusState),
+ TYPE_CPU_BUS, dev, "cpu-slot");
+ slot->bus.check_topology = slot_bus_check_topology;
+}
+
+static void cpu_slot_unrealize(DeviceState *dev)
+{
+ CPUSlot *slot = CPU_SLOT(dev);
+
+ device_listener_unregister(&slot->listener);
+}
+
+static void cpu_slot_class_init(ObjectClass *oc, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
+ dc->realize = cpu_slot_realize;
+ dc->unrealize = cpu_slot_unrealize;
+}
+
+static const TypeInfo cpu_slot_type_info = {
+ .name = TYPE_CPU_SLOT,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .class_init = cpu_slot_class_init,
+ .instance_size = sizeof(CPUSlot),
+};
+
+static void cpu_slot_register_types(void)
+{
+ type_register_static(&cpu_slot_type_info);
+}
+
+type_init(cpu_slot_register_types)
diff --git a/hw/cpu/meson.build b/hw/cpu/meson.build
index 6c6546646608..358e2b3960fa 100644
--- a/hw/cpu/meson.build
+++ b/hw/cpu/meson.build
@@ -1,6 +1,7 @@
common_ss.add(files('cpu-topology.c'))
system_ss.add(files('core.c'))
+system_ss.add(files('cpu-slot.c'))
system_ss.add(when: 'CONFIG_CPU_CLUSTER', if_true: files('cluster.c'))
system_ss.add(when: 'CONFIG_ARM11MPCORE', if_true: files('arm11mpcore.c'))
diff --git a/include/hw/cpu/cpu-slot.h b/include/hw/cpu/cpu-slot.h
new file mode 100644
index 000000000000..9d02d5de578e
--- /dev/null
+++ b/include/hw/cpu/cpu-slot.h
@@ -0,0 +1,72 @@
+/*
+ * CPU slot abstraction header
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * 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 CPU_SLOT_H
+#define CPU_SLOT_H
+
+#include "hw/cpu/cpu-topology.h"
+#include "hw/qdev-core.h"
+#include "hw/sysbus.h"
+#include "qapi/qapi-types-machine-common.h"
+#include "qom/object.h"
+
+/**
+ * CPUTopoStatEntry:
+ * @total_instances: Total number of topological instances at the same level
+ * that are currently inserted in CPU slot
+ * @max_instances: Maximum number of topological instances at the same level
+ * under the parent topological container
+ */
+typedef struct CPUTopoStatEntry {
+ int total_instances;
+ int max_instances;
+} CPUTopoStatEntry;
+
+/**
+ * CPUTopoStat:
+ * @entries: Detail count information for valid topology levels under
+ * CPU slot
+ * @curr_levels: Current CPU topology levels inserted in CPU slot
+ */
+typedef struct CPUTopoStat {
+ /* TODO: Exclude invalid and default levels. */
+ CPUTopoStatEntry entries[CPU_TOPOLOGY_LEVEL__MAX];
+ DECLARE_BITMAP(curr_levels, CPU_TOPOLOGY_LEVEL__MAX);
+} CPUTopoStat;
+
+#define TYPE_CPU_SLOT "cpu-slot"
+OBJECT_DECLARE_SIMPLE_TYPE(CPUSlot, CPU_SLOT)
+
+/**
+ * CPUSlot:
+ * @cores: Queue consisting of all the cores in the topology tree
+ * where the cpu-slot is the root. cpu-slot can maintain similar
+ * queues for other topology levels to facilitate traversal
+ * when necessary.
+ * @stat: Topological statistics for topology tree.
+ * @bus: CPU bus to add the children topology device.
+ * @supported_levels: Supported topology levels for topology tree.
+ * @listener: Hooks to listen realize() and unrealize() of topology
+ * device.
+ */
+struct CPUSlot {
+ /*< private >*/
+ SysBusDevice parent_obj;
+
+ /*< public >*/
+ CPUBusState bus;
+ CPUTopoStat stat;
+ DECLARE_BITMAP(supported_levels, CPU_TOPOLOGY_LEVEL__MAX);
+
+ DeviceListener listener;
+};
+
+#endif /* CPU_SLOT_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 05/15] qdev: Add method in BusClass to customize device index
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (3 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 04/15] hw/cpu: Introduce CPU slot to manage CPU topology Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 06/15] hw/core: Create CPU slot in MachineState to manage CPU topology tree Zhao Liu
` (9 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
Currently, when the bus assigns an index to a child device, it relies on
a monotonically increasing max_index.
However, when a device is removed from the bus, its index is not
reassigned to new devices, leading to "holes" in child indices.
For topology devices, such as CPUs/cores, arches define custom
sub-topology IDs. Some of these IDs are global (e.g., core-id for core
devices), while others are local (e.g., thread-id/core-id/module-id for
x86 CPUs).
Local IDs are indexes under the same parent device and align with
BusChild's index meaning. Therefore, local IDs in a topology context
should use BusChild.index.
Considering that topology devices support hot-plug and local IDs often
have range constraints, add a new method (BusClass.assign_free_index) to
allow the bus to customize index assignment.
Based on this method, the CPU bus will search for free index "holes"
created by unplugging and assign these free indices to newly inserted
devices.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
hw/core/qdev.c | 8 +++++++-
hw/cpu/cpu-topology.c | 37 +++++++++++++++++++++++++++++++++++
include/hw/cpu/cpu-topology.h | 1 +
include/hw/qdev-core.h | 2 ++
4 files changed, 47 insertions(+), 1 deletion(-)
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
index ff073cbff56d..e3e9f0f303d6 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -78,11 +78,17 @@ static void bus_remove_child(BusState *bus, DeviceState *child)
static void bus_add_child(BusState *bus, DeviceState *child)
{
+ BusClass *bc = BUS_GET_CLASS(bus);
char name[32];
BusChild *kid = g_malloc0(sizeof(*kid));
+ if (bc->assign_free_index) {
+ kid->index = bc->assign_free_index(bus);
+ } else {
+ kid->index = bus->max_index++;
+ }
+
bus->num_children++;
- kid->index = bus->max_index++;
kid->child = child;
child->bus_node = kid;
object_ref(OBJECT(kid->child));
diff --git a/hw/cpu/cpu-topology.c b/hw/cpu/cpu-topology.c
index e68c06132e7d..3e8982ff7e6c 100644
--- a/hw/cpu/cpu-topology.c
+++ b/hw/cpu/cpu-topology.c
@@ -49,11 +49,40 @@ static bool cpu_bus_check_address(BusState *bus, DeviceState *dev,
return cpu_parent_check_topology(bus->parent, dev, errp);
}
+static int cpu_bus_assign_free_index(BusState *bus)
+{
+ BusChild *kid;
+ int index;
+
+ if (bus->num_children == bus->max_index) {
+ return bus->max_index++;
+ }
+
+ assert(bus->num_children < bus->max_index);
+ /* TODO: Introduce the list sorted by index */
+ for (index = 0; index < bus->num_children; index++) {
+ bool existed = false;
+
+ QTAILQ_FOREACH(kid, &bus->children, sibling) {
+ if (kid->index == index) {
+ existed = true;
+ break;
+ }
+ }
+
+ if (!existed) {
+ break;
+ }
+ }
+ return index;
+}
+
static void cpu_bus_class_init(ObjectClass *oc, void *data)
{
BusClass *bc = BUS_CLASS(oc);
bc->check_address = cpu_bus_check_address;
+ bc->assign_free_index = cpu_bus_assign_free_index;
}
static const TypeInfo cpu_bus_type_info = {
@@ -177,3 +206,11 @@ int cpu_topo_get_instances_num(CPUTopoState *topo)
return bus ? bus->num_children : 1;
}
+
+int cpu_topo_get_index(CPUTopoState *topo)
+{
+ BusChild *node = DEVICE(topo)->bus_node;
+
+ assert(node);
+ return node->index;
+}
diff --git a/include/hw/cpu/cpu-topology.h b/include/hw/cpu/cpu-topology.h
index 7a447ad16ee7..80aeff18baa3 100644
--- a/include/hw/cpu/cpu-topology.h
+++ b/include/hw/cpu/cpu-topology.h
@@ -64,5 +64,6 @@ struct CPUTopoState {
#define GET_CPU_TOPO_LEVEL(topo) (CPU_TOPO_GET_CLASS(topo)->level)
int cpu_topo_get_instances_num(CPUTopoState *topo);
+int cpu_topo_get_index(CPUTopoState *topo);
#endif /* CPU_TOPO_H */
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
index 7cbc5fb97298..77223b28c788 100644
--- a/include/hw/qdev-core.h
+++ b/include/hw/qdev-core.h
@@ -342,6 +342,8 @@ struct BusClass {
*/
bool (*check_address)(BusState *bus, DeviceState *dev, Error **errp);
+ int (*assign_free_index)(BusState *bus);
+
BusRealize realize;
BusUnrealize unrealize;
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 06/15] hw/core: Create CPU slot in MachineState to manage CPU topology tree
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (4 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 05/15] qdev: Add method in BusClass to customize device index Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 07/15] hw/core/cpu: Convert CPU from general device to topology device Zhao Liu
` (8 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
With CPU slot support, the machine can manage the CPU topology tree. To
enable hot-plug support for topology devices, use the machine as the
hotplug handler for the CPU bus.
Additionally, since not all machines support the topology tree from the
start, add a "topo_tree_supported" flag to indicate whether a machine
supports the topology tree. And create the CPU slot as the topology root
only for machines that support it.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
hw/core/machine.c | 2 ++
hw/cpu/cpu-slot.c | 34 ++++++++++++++++++++++++++++++++++
include/hw/boards.h | 9 +++++++++
include/hw/cpu/cpu-slot.h | 2 ++
system/vl.c | 4 ++++
5 files changed, 51 insertions(+)
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 518beb9f883a..b6258d95b1e8 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -1239,6 +1239,8 @@ static void machine_initfn(Object *obj)
ms->smp_cache.props[i].topology = CPU_TOPOLOGY_LEVEL_DEFAULT;
}
+ ms->topo = NULL;
+
machine_copy_boot_config(ms, &(BootConfiguration){ 0 });
}
diff --git a/hw/cpu/cpu-slot.c b/hw/cpu/cpu-slot.c
index 66ef8d9faa97..4dbd5b7b7e00 100644
--- a/hw/cpu/cpu-slot.c
+++ b/hw/cpu/cpu-slot.c
@@ -138,3 +138,37 @@ static void cpu_slot_register_types(void)
}
type_init(cpu_slot_register_types)
+
+void machine_plug_cpu_slot(MachineState *ms)
+{
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ CPUSlot *slot;
+
+ slot = CPU_SLOT(qdev_new(TYPE_CPU_SLOT));
+ set_bit(CPU_TOPOLOGY_LEVEL_THREAD, slot->supported_levels);
+ set_bit(CPU_TOPOLOGY_LEVEL_CORE, slot->supported_levels);
+ set_bit(CPU_TOPOLOGY_LEVEL_SOCKET, slot->supported_levels);
+
+ /*
+ * Now just consider the levels that x86 supports.
+ * TODO: Supports other levels.
+ */
+ if (mc->smp_props.modules_supported) {
+ set_bit(CPU_TOPOLOGY_LEVEL_MODULE, slot->supported_levels);
+ }
+
+ if (mc->smp_props.dies_supported) {
+ set_bit(CPU_TOPOLOGY_LEVEL_DIE, slot->supported_levels);
+ }
+
+ ms->topo = slot;
+ object_property_add_child(container_get(OBJECT(ms), "/peripheral"),
+ "cpu-slot", OBJECT(ms->topo));
+ DEVICE(ms->topo)->id = g_strdup_printf("%s", "cpu-slot");
+
+ sysbus_realize(SYS_BUS_DEVICE(slot), &error_abort);
+
+ if (mc->get_hotplug_handler) {
+ qbus_set_hotplug_handler(BUS(&slot->bus), OBJECT(ms));
+ }
+}
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 2dd8decf640a..eeb4e7e2ce9f 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -10,6 +10,7 @@
#include "qemu/module.h"
#include "qom/object.h"
#include "hw/core/cpu.h"
+#include "hw/cpu/cpu-slot.h"
#define TYPE_MACHINE_SUFFIX "-machine"
@@ -152,6 +153,8 @@ typedef struct {
* @modules_supported - whether modules are supported by the machine
* @cache_supported - whether cache topologies (l1d, l1i, l2 and l3) are
* supported by the machine
+ * @topo_tree_supported - whether QOM topology tree is supported by the
+ * machine
*/
typedef struct {
bool prefer_sockets;
@@ -162,6 +165,7 @@ typedef struct {
bool drawers_supported;
bool modules_supported;
bool cache_supported[CACHE_LEVEL_AND_TYPE__MAX];
+ bool topo_tree_supported;
} SMPCompatProps;
/**
@@ -431,6 +435,11 @@ struct MachineState {
CPUArchIdList *possible_cpus;
CpuTopology smp;
SmpCache smp_cache;
+ /*
+ * TODO: get rid of "smp" and merge it into "topo" when all arches
+ * support QOM topology.
+ */
+ CPUSlot *topo;
struct NVDIMMState *nvdimms_state;
struct NumaState *numa_state;
};
diff --git a/include/hw/cpu/cpu-slot.h b/include/hw/cpu/cpu-slot.h
index 9d02d5de578e..24e122013bf7 100644
--- a/include/hw/cpu/cpu-slot.h
+++ b/include/hw/cpu/cpu-slot.h
@@ -69,4 +69,6 @@ struct CPUSlot {
DeviceListener listener;
};
+void machine_plug_cpu_slot(MachineState *ms);
+
#endif /* CPU_SLOT_H */
diff --git a/system/vl.c b/system/vl.c
index fe547ca47c27..193e7049ccbe 100644
--- a/system/vl.c
+++ b/system/vl.c
@@ -2151,6 +2151,10 @@ static void qemu_create_machine(QDict *qdict)
false, &error_abort);
qobject_unref(default_opts);
}
+
+ if (machine_class->smp_props.topo_tree_supported) {
+ machine_plug_cpu_slot(current_machine);
+ }
}
static int global_init_func(void *opaque, QemuOpts *opts, Error **errp)
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 07/15] hw/core/cpu: Convert CPU from general device to topology device
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (5 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 06/15] hw/core: Create CPU slot in MachineState to manage CPU topology tree Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 08/15] hw/cpu/core: Convert cpu-core " Zhao Liu
` (7 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
Convert CPU to topology device then it can be added into topology tree.
Because CPU then inherits properties and settings of topology device,
make the following changes to take into account the special case for CPU:
* Omit setting category since topology device has already set.
* Make realize() of topology device as the parent realize().
* Clean up some cases that assume parent obj is DeviceState and access
parent_obj directly.
* Set CPU's topology level as thread.
* And one complex change: mask bus_type as NULL.
- This is because for the arches don't support topology tree,
there's no CPU bus bridge so that CPUs of these arches can't be
created. So, only the CPU with arch supporting topology tree
should override the bus_type field.
* Further, support cpu_create() for the CPU with bus_type.
- This is a corner case, some arch CPUs may set bus_type, and
cpu_create() would be called in system emulation case (e.g., none
machine). To handle such case, try to find the machine's CPU bus
in cpu_create().
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
accel/kvm/kvm-all.c | 4 ++--
hw/core/cpu-common.c | 42 +++++++++++++++++++++++++++++++++++++-----
include/hw/core/cpu.h | 7 +++++--
target/ppc/kvm.c | 2 +-
4 files changed, 45 insertions(+), 10 deletions(-)
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index beb1988d12cf..48c040f6861d 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -4173,7 +4173,7 @@ static void query_stats(StatsResultList **result, StatsTarget target,
break;
case STATS_TARGET_VCPU:
add_stats_entry(result, STATS_PROVIDER_KVM,
- cpu->parent_obj.canonical_path,
+ DEVICE(cpu)->canonical_path,
stats_list);
break;
default:
@@ -4265,7 +4265,7 @@ static void query_stats_cb(StatsResultList **result, StatsTarget target,
stats_args.names = names;
stats_args.errp = errp;
CPU_FOREACH(cpu) {
- if (!apply_str_list_filter(cpu->parent_obj.canonical_path, targets)) {
+ if (!apply_str_list_filter(DEVICE(cpu)->canonical_path, targets)) {
continue;
}
query_stats_vcpu(cpu, &stats_args);
diff --git a/hw/core/cpu-common.c b/hw/core/cpu-common.c
index 7982ecd39a53..08f2d536ff6d 100644
--- a/hw/core/cpu-common.c
+++ b/hw/core/cpu-common.c
@@ -57,7 +57,19 @@ CPUState *cpu_create(const char *typename)
{
Error *err = NULL;
CPUState *cpu = CPU(object_new(typename));
- if (!qdev_realize(DEVICE(cpu), NULL, &err)) {
+ BusState *bus = NULL;
+
+ if (DEVICE_GET_CLASS(cpu)->bus_type) {
+ MachineState *ms;
+
+ ms = (MachineState *)object_dynamic_cast(qdev_get_machine(),
+ TYPE_MACHINE);
+ if (ms) {
+ bus = BUS(&ms->topo->bus);
+ }
+ }
+
+ if (!qdev_realize(DEVICE(cpu), bus, &err)) {
error_report_err(err);
object_unref(OBJECT(cpu));
exit(EXIT_FAILURE);
@@ -196,6 +208,12 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cpu = CPU(dev);
Object *machine = qdev_get_machine();
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ cc->parent_realize(dev, errp);
+ if (*errp) {
+ return;
+ }
/* qdev_get_machine() can return something that's not TYPE_MACHINE
* if this is one of the user-only emulators; in that case there's
@@ -302,6 +320,7 @@ static void cpu_common_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
+ CPUTopoClass *tc = CPU_TOPO_CLASS(klass);
CPUClass *k = CPU_CLASS(klass);
k->parse_features = cpu_common_parse_features;
@@ -309,9 +328,6 @@ static void cpu_common_class_init(ObjectClass *klass, void *data)
k->has_work = cpu_common_has_work;
k->gdb_read_register = cpu_common_gdb_read_register;
k->gdb_write_register = cpu_common_gdb_write_register;
- set_bit(DEVICE_CATEGORY_CPU, dc->categories);
- dc->realize = cpu_common_realizefn;
- dc->unrealize = cpu_common_unrealizefn;
rc->phases.hold = cpu_common_reset_hold;
cpu_class_init_props(dc);
/*
@@ -319,11 +335,27 @@ static void cpu_common_class_init(ObjectClass *klass, void *data)
* IRQs, adding reset handlers, halting non-first CPUs, ...
*/
dc->user_creatable = false;
+ /*
+ * CPU is the minimum granularity for hotplug in most case, and
+ * often its hotplug handler is ultimately decided by the machine.
+ * For generality, set this flag to avoid blocking possible hotplug
+ * support.
+ */
+ dc->hotpluggable = true;
+ device_class_set_parent_realize(dc, cpu_common_realizefn,
+ &k->parent_realize);
+ dc->unrealize = cpu_common_unrealizefn;
+ /*
+ * Avoid archs that do not support topology device trees from
+ * encountering error when creating CPUs.
+ */
+ dc->bus_type = NULL;
+ tc->level = CPU_TOPOLOGY_LEVEL_THREAD;
}
static const TypeInfo cpu_type_info = {
.name = TYPE_CPU,
- .parent = TYPE_DEVICE,
+ .parent = TYPE_CPU_TOPO,
.instance_size = sizeof(CPUState),
.instance_init = cpu_common_initfn,
.instance_finalize = cpu_common_finalize,
diff --git a/include/hw/core/cpu.h b/include/hw/core/cpu.h
index 1c9c775df658..d7268bcb48cb 100644
--- a/include/hw/core/cpu.h
+++ b/include/hw/core/cpu.h
@@ -20,6 +20,7 @@
#ifndef QEMU_CPU_H
#define QEMU_CPU_H
+#include "hw/cpu/cpu-topology.h"
#include "hw/qdev-core.h"
#include "disas/dis-asm.h"
#include "exec/breakpoint.h"
@@ -144,7 +145,7 @@ struct SysemuCPUOps;
*/
struct CPUClass {
/*< private >*/
- DeviceClass parent_class;
+ CPUTopoClass parent_class;
/*< public >*/
ObjectClass *(*class_by_name)(const char *cpu_model);
@@ -189,6 +190,8 @@ struct CPUClass {
int reset_dump_flags;
int gdb_num_core_regs;
bool gdb_stop_before_watchpoint;
+
+ DeviceRealize parent_realize;
};
/*
@@ -456,7 +459,7 @@ struct qemu_work_item;
*/
struct CPUState {
/*< private >*/
- DeviceState parent_obj;
+ CPUTopoState parent_obj;
/* cache to avoid expensive CPU_GET_CLASS */
CPUClass *cc;
/*< public >*/
diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c
index 907dba60d1b5..b3cc42e545af 100644
--- a/target/ppc/kvm.c
+++ b/target/ppc/kvm.c
@@ -2351,7 +2351,7 @@ static void alter_insns(uint64_t *word, uint64_t flags, bool on)
static bool kvmppc_cpu_realize(CPUState *cs, Error **errp)
{
int ret;
- const char *vcpu_str = (cs->parent_obj.hotplugged == true) ?
+ const char *vcpu_str = (DEVICE(cs)->hotplugged == true) ?
"hotplug" : "create";
cs->cpu_index = cpu_get_free_index();
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 08/15] hw/cpu/core: Convert cpu-core from general device to topology device
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (6 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 07/15] hw/core/cpu: Convert CPU from general device to topology device Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 09/15] hw/cpu: Abstract module/die/socket levels as topology devices Zhao Liu
` (6 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
Convert cpu-core to topology device then it can be added into topology
tree.
At present, only PPC is using cpu-core device. For topology tree, it's
necessary to add cpu-core in the tree as one of the topology
hierarchies.
The generic cpu-core is sufficient to express the core layer in a
topology tree without needing to consider any arch-specific feature, so
to reduce the support complexity of the topology tree and allow arch to
be able to use the abstract cpu-core directly, without further
derivation of the arch-specific core, remove the "abstract" restriction
from TypeInfo.
Because cpu-core then inherits properties and settings of topology
device, also make the following changes to take into account the special
case for cpu-core:
* Omit setting category since topology device has already set.
* Make realize() of topology device as the parent realize() for PPC
cores.
* Set cpu-core's topology level as core.
* Mask bus_type for PPC cores as NULL to avoid PPC cores' creation
failure since PPC currently doesn't support topology tree.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
hw/cpu/core.c | 9 +++++----
hw/ppc/pnv_core.c | 11 ++++++++++-
hw/ppc/spapr_cpu_core.c | 12 +++++++++++-
include/hw/cpu/core.h | 3 ++-
include/hw/ppc/pnv_core.h | 3 ++-
include/hw/ppc/spapr_cpu_core.h | 4 +++-
6 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/hw/cpu/core.c b/hw/cpu/core.c
index 495a5c30ffe1..bf1cbceea21b 100644
--- a/hw/cpu/core.c
+++ b/hw/cpu/core.c
@@ -79,19 +79,20 @@ static void cpu_core_instance_init(Object *obj)
static void cpu_core_class_init(ObjectClass *oc, void *data)
{
- DeviceClass *dc = DEVICE_CLASS(oc);
+ CPUTopoClass *tc = CPU_TOPO_CLASS(oc);
- set_bit(DEVICE_CATEGORY_CPU, dc->categories);
+ /* TODO: Offload "core-id" and "nr-threads" to ppc-specific core. */
object_class_property_add(oc, "core-id", "int", core_prop_get_core_id,
core_prop_set_core_id, NULL, NULL);
object_class_property_add(oc, "nr-threads", "int", core_prop_get_nr_threads,
core_prop_set_nr_threads, NULL, NULL);
+
+ tc->level = CPU_TOPOLOGY_LEVEL_CORE;
}
static const TypeInfo cpu_core_type_info = {
.name = TYPE_CPU_CORE,
- .parent = TYPE_DEVICE,
- .abstract = true,
+ .parent = TYPE_CPU_TOPO,
.class_init = cpu_core_class_init,
.instance_size = sizeof(CPUCore),
.instance_init = cpu_core_instance_init,
diff --git a/hw/ppc/pnv_core.c b/hw/ppc/pnv_core.c
index a30693990b25..9be7a4b6c1a9 100644
--- a/hw/ppc/pnv_core.c
+++ b/hw/ppc/pnv_core.c
@@ -356,6 +356,8 @@ static void pnv_core_realize(DeviceState *dev, Error **errp)
assert(pc->chip);
+ pcc->parent_realize(dev, errp);
+
pc->threads = g_new(PowerPCCPU *, cc->nr_threads);
for (i = 0; i < cc->nr_threads; i++) {
PowerPCCPU *cpu;
@@ -466,11 +468,18 @@ static void pnv_core_power10_class_init(ObjectClass *oc, void *data)
static void pnv_core_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
+ PnvCoreClass *pcc = PNV_CORE_CLASS(oc);
- dc->realize = pnv_core_realize;
dc->unrealize = pnv_core_unrealize;
device_class_set_props(dc, pnv_core_properties);
dc->user_creatable = false;
+ device_class_set_parent_realize(dc, pnv_core_realize,
+ &pcc->parent_realize);
+ /*
+ * Avoid ppc that do not support topology device trees from
+ * encountering error when creating cores.
+ */
+ dc->bus_type = NULL;
}
#define DEFINE_PNV_CORE_TYPE(family, cpu_model) \
diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c
index 464224516881..49c440fc0e09 100644
--- a/hw/ppc/spapr_cpu_core.c
+++ b/hw/ppc/spapr_cpu_core.c
@@ -338,6 +338,7 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
(SpaprMachineState *) object_dynamic_cast(qdev_get_machine(),
TYPE_SPAPR_MACHINE);
SpaprCpuCore *sc = SPAPR_CPU_CORE(OBJECT(dev));
+ SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_GET_CLASS(sc);
CPUCore *cc = CPU_CORE(OBJECT(dev));
int i;
@@ -346,6 +347,8 @@ static void spapr_cpu_core_realize(DeviceState *dev, Error **errp)
return;
}
+ scc->parent_realize(dev, errp);
+
qemu_register_reset(spapr_cpu_core_reset_handler, sc);
sc->threads = g_new0(PowerPCCPU *, cc->nr_threads);
for (i = 0; i < cc->nr_threads; i++) {
@@ -376,11 +379,18 @@ static void spapr_cpu_core_class_init(ObjectClass *oc, void *data)
DeviceClass *dc = DEVICE_CLASS(oc);
SpaprCpuCoreClass *scc = SPAPR_CPU_CORE_CLASS(oc);
- dc->realize = spapr_cpu_core_realize;
dc->unrealize = spapr_cpu_core_unrealize;
device_class_set_legacy_reset(dc, spapr_cpu_core_reset);
device_class_set_props(dc, spapr_cpu_core_properties);
+ dc->hotpluggable = true;
scc->cpu_type = data;
+ device_class_set_parent_realize(dc, spapr_cpu_core_realize,
+ &scc->parent_realize);
+ /*
+ * Avoid ppc that do not support topology device trees from
+ * encountering error when creating cores.
+ */
+ dc->bus_type = NULL;
}
#define DEFINE_SPAPR_CPU_CORE_TYPE(cpu_model) \
diff --git a/include/hw/cpu/core.h b/include/hw/cpu/core.h
index 98ab91647eb2..a451dcd2e4d8 100644
--- a/include/hw/cpu/core.h
+++ b/include/hw/cpu/core.h
@@ -9,6 +9,7 @@
#ifndef HW_CPU_CORE_H
#define HW_CPU_CORE_H
+#include "hw/cpu/cpu-topology.h"
#include "hw/qdev-core.h"
#include "qom/object.h"
@@ -18,7 +19,7 @@ OBJECT_DECLARE_SIMPLE_TYPE(CPUCore, CPU_CORE)
struct CPUCore {
/*< private >*/
- DeviceState parent_obj;
+ CPUTopoState parent_obj;
/*< public >*/
int core_id;
diff --git a/include/hw/ppc/pnv_core.h b/include/hw/ppc/pnv_core.h
index d8afb4f95f92..252b98ae20f9 100644
--- a/include/hw/ppc/pnv_core.h
+++ b/include/hw/ppc/pnv_core.h
@@ -71,10 +71,11 @@ struct PnvCore {
};
struct PnvCoreClass {
- DeviceClass parent_class;
+ CPUTopoClass parent_class;
const MemoryRegionOps *xscom_ops;
uint64_t xscom_size;
+ DeviceRealize parent_realize;
};
#define PNV_CORE_TYPE_SUFFIX "-" TYPE_PNV_CORE
diff --git a/include/hw/ppc/spapr_cpu_core.h b/include/hw/ppc/spapr_cpu_core.h
index 69a52e39b850..fc6c15747a88 100644
--- a/include/hw/ppc/spapr_cpu_core.h
+++ b/include/hw/ppc/spapr_cpu_core.h
@@ -32,8 +32,10 @@ struct SpaprCpuCore {
};
struct SpaprCpuCoreClass {
- DeviceClass parent_class;
+ CPUTopoClass parent_class;
+
const char *cpu_type;
+ DeviceRealize parent_realize;
};
const char *spapr_get_cpu_core_type(const char *cpu_type);
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 09/15] hw/cpu: Abstract module/die/socket levels as topology devices
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (7 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 08/15] hw/cpu/core: Convert cpu-core " Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 10/15] hw/machine: Build smp topology tree from -smp Zhao Liu
` (5 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
Abstract module/die/socket levels as the cpu-module/cpu-die/cpu-socket
topology devices then they can be inserted into topology tree.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
MAINTAINERS | 6 ++++++
hw/cpu/die.c | 34 ++++++++++++++++++++++++++++++++++
hw/cpu/meson.build | 3 +++
hw/cpu/module.c | 34 ++++++++++++++++++++++++++++++++++
hw/cpu/socket.c | 34 ++++++++++++++++++++++++++++++++++
include/hw/cpu/die.h | 29 +++++++++++++++++++++++++++++
include/hw/cpu/module.h | 29 +++++++++++++++++++++++++++++
include/hw/cpu/socket.h | 29 +++++++++++++++++++++++++++++
8 files changed, 198 insertions(+)
create mode 100644 hw/cpu/die.c
create mode 100644 hw/cpu/module.c
create mode 100644 hw/cpu/socket.c
create mode 100644 include/hw/cpu/die.h
create mode 100644 include/hw/cpu/module.h
create mode 100644 include/hw/cpu/socket.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 8e5b2cd91dca..03c1a13de074 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1886,6 +1886,9 @@ F: hw/core/numa.c
F: hw/cpu/cluster.c
F: hw/cpu/cpu-slot.c
F: hw/cpu/cpu-topology.c
+F: hw/cpu/die.c
+F: hw/cpu/module.c
+F: hw/cpu/socket.c
F: qapi/machine.json
F: qapi/machine-common.json
F: qapi/machine-target.json
@@ -1894,6 +1897,9 @@ F: include/hw/core/cpu.h
F: include/hw/cpu/cluster.h
F: include/hw/cpu/cpu-slot.h
F: include/hw/cpu/cpu-topology.h
+F: include/hw/cpu/die.h
+F: include/hw/cpu/module.h
+F: include/hw/cpu/socket.h
F: include/sysemu/numa.h
F: tests/functional/test_cpu_queries.py
F: tests/functional/test_empty_cpu_model.py
diff --git a/hw/cpu/die.c b/hw/cpu/die.c
new file mode 100644
index 000000000000..f00907ffd78b
--- /dev/null
+++ b/hw/cpu/die.c
@@ -0,0 +1,34 @@
+/*
+ * CPU die abstract device
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * 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/cpu/die.h"
+
+static void cpu_die_class_init(ObjectClass *oc, void *data)
+{
+ CPUTopoClass *tc = CPU_TOPO_CLASS(oc);
+
+ tc->level = CPU_TOPOLOGY_LEVEL_DIE;
+}
+
+static const TypeInfo cpu_die_type_info = {
+ .name = TYPE_CPU_DIE,
+ .parent = TYPE_CPU_TOPO,
+ .class_init = cpu_die_class_init,
+ .instance_size = sizeof(CPUDie),
+};
+
+static void cpu_die_register_types(void)
+{
+ type_register_static(&cpu_die_type_info);
+}
+
+type_init(cpu_die_register_types)
diff --git a/hw/cpu/meson.build b/hw/cpu/meson.build
index 358e2b3960fa..c64eec4460d8 100644
--- a/hw/cpu/meson.build
+++ b/hw/cpu/meson.build
@@ -3,6 +3,9 @@ common_ss.add(files('cpu-topology.c'))
system_ss.add(files('core.c'))
system_ss.add(files('cpu-slot.c'))
system_ss.add(when: 'CONFIG_CPU_CLUSTER', if_true: files('cluster.c'))
+system_ss.add(files('die.c'))
+system_ss.add(files('module.c'))
+system_ss.add(files('socket.c'))
system_ss.add(when: 'CONFIG_ARM11MPCORE', if_true: files('arm11mpcore.c'))
system_ss.add(when: 'CONFIG_REALVIEW', if_true: files('realview_mpcore.c'))
diff --git a/hw/cpu/module.c b/hw/cpu/module.c
new file mode 100644
index 000000000000..b6f50a2ba588
--- /dev/null
+++ b/hw/cpu/module.c
@@ -0,0 +1,34 @@
+/*
+ * CPU module abstract device
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * 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/cpu/module.h"
+
+static void cpu_module_class_init(ObjectClass *oc, void *data)
+{
+ CPUTopoClass *tc = CPU_TOPO_CLASS(oc);
+
+ tc->level = CPU_TOPOLOGY_LEVEL_MODULE;
+}
+
+static const TypeInfo cpu_module_type_info = {
+ .name = TYPE_CPU_MODULE,
+ .parent = TYPE_CPU_TOPO,
+ .class_init = cpu_module_class_init,
+ .instance_size = sizeof(CPUModule),
+};
+
+static void cpu_module_register_types(void)
+{
+ type_register_static(&cpu_module_type_info);
+}
+
+type_init(cpu_module_register_types)
diff --git a/hw/cpu/socket.c b/hw/cpu/socket.c
new file mode 100644
index 000000000000..516e93389e11
--- /dev/null
+++ b/hw/cpu/socket.c
@@ -0,0 +1,34 @@
+/*
+ * CPU socket abstract device
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * 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/cpu/socket.h"
+
+static void cpu_socket_class_init(ObjectClass *oc, void *data)
+{
+ CPUTopoClass *tc = CPU_TOPO_CLASS(oc);
+
+ tc->level = CPU_TOPOLOGY_LEVEL_SOCKET;
+}
+
+static const TypeInfo cpu_socket_type_info = {
+ .name = TYPE_CPU_SOCKET,
+ .parent = TYPE_CPU_TOPO,
+ .class_init = cpu_socket_class_init,
+ .instance_size = sizeof(CPUSocket),
+};
+
+static void cpu_socket_register_types(void)
+{
+ type_register_static(&cpu_socket_type_info);
+}
+
+type_init(cpu_socket_register_types)
diff --git a/include/hw/cpu/die.h b/include/hw/cpu/die.h
new file mode 100644
index 000000000000..682e226ac569
--- /dev/null
+++ b/include/hw/cpu/die.h
@@ -0,0 +1,29 @@
+/*
+ * CPU die abstract device
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * 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 HW_CPU_DIE_H
+#define HW_CPU_DIE_H
+
+#include "hw/cpu/cpu-topology.h"
+#include "hw/qdev-core.h"
+
+#define TYPE_CPU_DIE "cpu-die"
+
+OBJECT_DECLARE_SIMPLE_TYPE(CPUDie, CPU_DIE)
+
+struct CPUDie {
+ /*< private >*/
+ CPUTopoState obj;
+
+ /*< public >*/
+};
+
+#endif /* HW_CPU_DIE_H */
diff --git a/include/hw/cpu/module.h b/include/hw/cpu/module.h
new file mode 100644
index 000000000000..242cd623a3b3
--- /dev/null
+++ b/include/hw/cpu/module.h
@@ -0,0 +1,29 @@
+/*
+ * CPU module abstract device
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * 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 HW_CPU_MODULE_H
+#define HW_CPU_MODULE_H
+
+#include "hw/cpu/cpu-topology.h"
+#include "hw/qdev-core.h"
+
+#define TYPE_CPU_MODULE "cpu-module"
+
+OBJECT_DECLARE_SIMPLE_TYPE(CPUModule, CPU_MODULE)
+
+struct CPUModule {
+ /*< private >*/
+ CPUTopoState obj;
+
+ /*< public >*/
+};
+
+#endif /* HW_CPU_MODULE_H */
diff --git a/include/hw/cpu/socket.h b/include/hw/cpu/socket.h
new file mode 100644
index 000000000000..a25bf8727a22
--- /dev/null
+++ b/include/hw/cpu/socket.h
@@ -0,0 +1,29 @@
+/*
+ * CPU socket abstract device
+ *
+ * Copyright (C) 2024 Intel Corporation.
+ *
+ * Author: Zhao Liu <zhao1.liu@intel.com>
+ *
+ * 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 HW_CPU_SOCKET_H
+#define HW_CPU_SOCKET_H
+
+#include "hw/cpu/cpu-topology.h"
+#include "hw/qdev-core.h"
+
+#define TYPE_CPU_SOCKET "cpu-socket"
+
+OBJECT_DECLARE_SIMPLE_TYPE(CPUSocket, CPU_SOCKET)
+
+struct CPUSocket {
+ /*< private >*/
+ CPUTopoState parent_obj;
+
+ /*< public >*/
+};
+
+#endif /* HW_CPU_SOCKET_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 10/15] hw/machine: Build smp topology tree from -smp
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (8 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 09/15] hw/cpu: Abstract module/die/socket levels as topology devices Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 11/15] hw/core: Support topology tree in none machine for compatibility Zhao Liu
` (4 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
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(+)
diff --git a/hw/core/machine.c b/hw/core/machine.c
index b6258d95b1e8..076bd365197b 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -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);
diff --git a/hw/cpu/cpu-slot.c b/hw/cpu/cpu-slot.c
index 4dbd5b7b7e00..1cc3b32ed675 100644
--- a/hw/cpu/cpu-slot.c
+++ b/hw/cpu/cpu-slot.c
@@ -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;
+}
diff --git a/include/hw/boards.h b/include/hw/boards.h
index eeb4e7e2ce9f..a49677466ef6 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -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;
/**
diff --git a/include/hw/cpu/cpu-slot.h b/include/hw/cpu/cpu-slot.h
index 24e122013bf7..1838e8c0c3f9 100644
--- a/include/hw/cpu/cpu-slot.h
+++ b/include/hw/cpu/cpu-slot.h
@@ -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 */
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index 2c0a2fe7512d..d1c0e52219de 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.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
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 11/15] hw/core: Support topology tree in none machine for compatibility
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (9 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 10/15] hw/machine: Build smp topology tree from -smp Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 12/15] hw/i386: Allow i386 to create new CPUs in topology tree Zhao Liu
` (3 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
None machine accepts any CPU types, even some CPUs may have the
bus_type.
To address this, set topo_tree_supported as true for none machine, then
none machine will have a CPU slot with CPU bus to collect any topology
device with bus_type specified.
And since arch_id_topo_level is not set, the topology devices will be
directly inserted under the CPU slot without being organized into a tree
structure.
For the CPUs without bus_type, topo_tree_supported will not affect them.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
hw/core/null-machine.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/hw/core/null-machine.c b/hw/core/null-machine.c
index f586a4bef543..101649f3e8c1 100644
--- a/hw/core/null-machine.c
+++ b/hw/core/null-machine.c
@@ -54,6 +54,11 @@ static void machine_none_machine_init(MachineClass *mc)
mc->no_floppy = 1;
mc->no_cdrom = 1;
mc->no_sdcard = 1;
+ /*
+ * For compatibility with arches and CPUs that already
+ * support topology tree.
+ */
+ mc->smp_props.topo_tree_supported = true;
}
DEFINE_MACHINE("none", machine_none_machine_init)
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 12/15] hw/i386: Allow i386 to create new CPUs in topology tree
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (10 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 11/15] hw/core: Support topology tree in none machine for compatibility Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 13/15] system/qdev-monitor: Introduce bus-finder interface for compatibility with bus-less plug behavior Zhao Liu
` (2 subsequent siblings)
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
For x86, CPU's apic ID represent its topology path and is the
combination of topology sub IDs in each leavl.
When x86 machine creates CPUs, to insert the CPU into topology tree, use
apic ID to get topology sub IDs.
Then search the topology tree for the corresponding parent topology
device and insert the CPU into the CPU bus of the parent device.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
hw/i386/x86-common.c | 101 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 97 insertions(+), 4 deletions(-)
diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index b21d2ab97349..a7f082b0a90b 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -53,14 +53,107 @@
/* Physical Address of PVH entry point read from kernel ELF NOTE */
static size_t pvh_start_addr;
-static void x86_cpu_new(X86MachineState *x86ms, int64_t apic_id, Error **errp)
+static int x86_cpu_get_topo_id(const X86CPUTopoIDs *topo_ids,
+ CpuTopologyLevel level)
{
- Object *cpu = object_new(MACHINE(x86ms)->cpu_type);
+ switch (level) {
+ case CPU_TOPOLOGY_LEVEL_THREAD:
+ return topo_ids->smt_id;
+ case CPU_TOPOLOGY_LEVEL_CORE:
+ return topo_ids->core_id;
+ case CPU_TOPOLOGY_LEVEL_MODULE:
+ return topo_ids->module_id;
+ case CPU_TOPOLOGY_LEVEL_DIE:
+ return topo_ids->die_id;
+ case CPU_TOPOLOGY_LEVEL_SOCKET:
+ return topo_ids->pkg_id;
+ default:
+ g_assert_not_reached();
+ }
+
+ return -1;
+}
+
+typedef struct SearchCoreCb {
+ const X86CPUTopoIDs *topo_ids;
+ const CPUTopoState *parent;
+} SearchCoreCb;
+
+static int x86_search_topo_parent(DeviceState *dev, void *opaque)
+{
+ CPUTopoState *topo = CPU_TOPO(dev);
+ CpuTopologyLevel level = GET_CPU_TOPO_LEVEL(topo);
+ SearchCoreCb *cb = opaque;
+ int topo_id, index;
+
+ topo_id = x86_cpu_get_topo_id(cb->topo_ids, level);
+ index = cpu_topo_get_index(topo);
+
+ if (topo_id < 0) {
+ error_report("Invalid %s-id: %d",
+ CpuTopologyLevel_str(level), topo_id);
+ error_printf("Try to set the %s-id in [0-%d].\n",
+ CpuTopologyLevel_str(level),
+ cpu_topo_get_instances_num(topo) - 1);
+ return TOPO_FOREACH_ERR;
+ }
+
+ if (topo_id == index) {
+ if (level == CPU_TOPOLOGY_LEVEL_CORE) {
+ cb->parent = topo;
+ /* The error result could exit directly. */
+ return TOPO_FOREACH_ERR;
+ }
+ return TOPO_FOREACH_CONTINUE;
+ }
+ return TOPO_FOREACH_END;
+}
+
+static BusState *x86_find_topo_bus(MachineState *ms, X86CPUTopoIDs *topo_ids)
+{
+ SearchCoreCb cb;
+
+ cb.topo_ids = topo_ids;
+ cb.parent = NULL;
+ qbus_walk_children(BUS(&ms->topo->bus), x86_search_topo_parent,
+ NULL, NULL, NULL, &cb);
+
+ if (!cb.parent) {
+ return NULL;
+ }
+
+ return BUS(cb.parent->bus);
+}
+
+static void x86_cpu_new(X86MachineState *x86ms, int index,
+ int64_t apic_id, Error **errp)
+{
+ MachineState *ms = MACHINE(x86ms);
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
+ Object *cpu = object_new(ms->cpu_type);
+ DeviceState *dev = DEVICE(cpu);
+ BusState *bus = NULL;
+
+ /*
+ * Once x86 machine supports topo_tree_supported, x86 CPU would
+ * also have bus_type.
+ */
+ if (mc->smp_props.topo_tree_supported) {
+ X86CPUTopoIDs topo_ids;
+ X86CPUTopoInfo topo_info;
+
+ init_topo_info(&topo_info, x86ms);
+ x86_topo_ids_from_apicid(apic_id, &topo_info, &topo_ids);
+ bus = x86_find_topo_bus(ms, &topo_ids);
+
+ /* Only with dev->id, CPU can be inserted into topology tree. */
+ dev->id = g_strdup_printf("%s[%d]", ms->cpu_type, index);
+ }
if (!object_property_set_uint(cpu, "apic-id", apic_id, errp)) {
goto out;
}
- qdev_realize(DEVICE(cpu), NULL, errp);
+ qdev_realize(dev, bus, errp);
out:
object_unref(cpu);
@@ -111,7 +204,7 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version)
possible_cpus = mc->possible_cpu_arch_ids(ms);
for (i = 0; i < ms->smp.cpus; i++) {
- x86_cpu_new(x86ms, possible_cpus->cpus[i].arch_id, &error_fatal);
+ x86_cpu_new(x86ms, i, possible_cpus->cpus[i].arch_id, &error_fatal);
}
}
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 13/15] system/qdev-monitor: Introduce bus-finder interface for compatibility with bus-less plug behavior
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (11 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 12/15] hw/i386: Allow i386 to create new CPUs in topology tree Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 14/15] i386/cpu: Support CPU plugged in topology tree via bus-finder Zhao Liu
2024-09-19 1:55 ` [RFC v2 15/15] i386: Support topology device tree Zhao Liu
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
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@intel.com>
---
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@intel.com>
+ *
+ * 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@intel.com>
+ *
+ * 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
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 14/15] i386/cpu: Support CPU plugged in topology tree via bus-finder
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (12 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 13/15] system/qdev-monitor: Introduce bus-finder interface for compatibility with bus-less plug behavior Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
2024-09-19 1:55 ` [RFC v2 15/15] i386: Support topology device tree Zhao Liu
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
Use topology sub IDs or APIC ID to locate parent topology device and
bus.
This process naturally verifies the correctness of topology-related IDs,
making it possible to drop the existing topology ID sanity checks once
x86 machine supports topology tree.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
hw/i386/x86-common.c | 99 ++++++++++++++++++++++++++++++++++---------
include/hw/i386/x86.h | 2 +
target/i386/cpu.c | 11 +++++
3 files changed, 91 insertions(+), 21 deletions(-)
diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index a7f082b0a90b..d837aadc9dea 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -208,6 +208,65 @@ void x86_cpus_init(X86MachineState *x86ms, int default_cpu_version)
}
}
+static void x86_fixup_topo_ids(MachineState *ms, X86CPU *cpu)
+{
+ /*
+ * die-id was optional in QEMU 4.0 and older, so keep it optional
+ * if there's only one die per socket.
+ */
+ if (cpu->module_id < 0 && ms->smp.modules == 1) {
+ cpu->module_id = 0;
+ }
+
+ /*
+ * module-id was optional in QEMU 9.0 and older, so keep it optional
+ * if there's only one module per die.
+ */
+ if (cpu->die_id < 0 && ms->smp.dies == 1) {
+ cpu->die_id = 0;
+ }
+}
+
+BusState *x86_cpu_get_parent_bus(DeviceState *dev)
+{
+ MachineState *ms = MACHINE(qdev_get_machine());
+ X86MachineState *x86ms = X86_MACHINE(ms);
+ X86CPU *cpu = X86_CPU(dev);
+ X86CPUTopoIDs topo_ids;
+ X86CPUTopoInfo topo_info;
+ BusState *bus;
+
+ x86_fixup_topo_ids(ms, cpu);
+ init_topo_info(&topo_info, x86ms);
+
+ if (cpu->apic_id == UNASSIGNED_APIC_ID) {
+ /* TODO: Make the thread_id and bus index of CPU the same. */
+ topo_ids.smt_id = cpu->thread_id;
+ topo_ids.core_id = cpu->core_id;
+ topo_ids.module_id = cpu->module_id;
+ topo_ids.die_id = cpu->die_id;
+ topo_ids.pkg_id = cpu->socket_id;
+ } else {
+ x86_topo_ids_from_apicid(cpu->apic_id, &topo_info, &topo_ids);
+ }
+
+ bus = x86_find_topo_bus(ms, &topo_ids);
+
+ /*
+ * If APIC ID is not set,
+ * set it based on socket/die/module/core/thread properties.
+ *
+ * The children walking result proves topo ids are valid.
+ * Though module and die are optional, topology tree will create
+ * at least 1 instance by default if the machine supports.
+ */
+ if (bus && cpu->apic_id == UNASSIGNED_APIC_ID) {
+ cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids);
+ }
+
+ return bus;
+}
+
void x86_rtc_set_cpus_count(ISADevice *s, uint16_t cpus_count)
{
MC146818RtcState *rtc = MC146818_RTC(s);
@@ -340,6 +399,7 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
X86CPU *cpu = X86_CPU(dev);
CPUX86State *env = &cpu->env;
MachineState *ms = MACHINE(hotplug_dev);
+ MachineClass *mc = MACHINE_GET_CLASS(ms);
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
unsigned int smp_cores = ms->smp.cores;
unsigned int smp_threads = ms->smp.threads;
@@ -374,26 +434,9 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
set_bit(CPU_TOPOLOGY_LEVEL_DIE, env->avail_cpu_topo);
}
- /*
- * If APIC ID is not set,
- * set it based on socket/die/module/core/thread properties.
- */
- if (cpu->apic_id == UNASSIGNED_APIC_ID) {
- /*
- * die-id was optional in QEMU 4.0 and older, so keep it optional
- * if there's only one die per socket.
- */
- if (cpu->die_id < 0 && ms->smp.dies == 1) {
- cpu->die_id = 0;
- }
-
- /*
- * module-id was optional in QEMU 9.0 and older, so keep it optional
- * if there's only one module per die.
- */
- if (cpu->module_id < 0 && ms->smp.modules == 1) {
- cpu->module_id = 0;
- }
+ if (cpu->apic_id == UNASSIGNED_APIC_ID &&
+ !mc->smp_props.topo_tree_supported) {
+ x86_fixup_topo_ids(ms, cpu);
if (cpu->socket_id < 0) {
error_setg(errp, "CPU socket-id is not set");
@@ -409,7 +452,6 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
} else if (cpu->die_id > ms->smp.dies - 1) {
error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u",
cpu->die_id, ms->smp.dies - 1);
- return;
}
if (cpu->module_id < 0) {
error_setg(errp, "CPU module-id is not set");
@@ -442,6 +484,21 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
topo_ids.core_id = cpu->core_id;
topo_ids.smt_id = cpu->thread_id;
cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids);
+ } else if (cpu->apic_id == UNASSIGNED_APIC_ID &&
+ mc->smp_props.topo_tree_supported) {
+ /*
+ * For this case, CPU is added by specifying the bus. Under the
+ * topology tree, specifying only the bus should be feasible, but
+ * the topology represented by the bus, topo ids, or apic id must
+ * be consistent.
+ *
+ * To simplify, the case with only the bus specified is not supported
+ * at this time.
+ */
+ if (x86_cpu_get_parent_bus(dev) != dev->parent_bus) {
+ error_setg(errp, "Invalid CPU topology ids");
+ return;
+ }
}
cpu_slot = x86_find_cpu_slot(MACHINE(x86ms), cpu->apic_id, &idx);
diff --git a/include/hw/i386/x86.h b/include/hw/i386/x86.h
index d43cb3908e65..2a62b4b8d08c 100644
--- a/include/hw/i386/x86.h
+++ b/include/hw/i386/x86.h
@@ -138,6 +138,8 @@ void x86_load_linux(X86MachineState *x86ms,
bool x86_machine_is_smm_enabled(const X86MachineState *x86ms);
bool x86_machine_is_acpi_enabled(const X86MachineState *x86ms);
+BusState *x86_cpu_get_parent_bus(DeviceState *dev);
+
/* Global System Interrupts */
#define ACPI_BUILD_PCI_IRQS ((1<<5) | (1<<9) | (1<<10) | (1<<11))
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 6d9f7dc0872a..90221ceb7313 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -35,12 +35,14 @@
#include "standard-headers/asm-x86/kvm_para.h"
#include "hw/qdev-properties.h"
#include "hw/i386/topology.h"
+#include "monitor/bus-finder.h"
#ifndef CONFIG_USER_ONLY
#include "sysemu/reset.h"
#include "qapi/qapi-commands-machine-target.h"
#include "exec/address-spaces.h"
#include "hw/boards.h"
#include "hw/i386/sgx-epc.h"
+#include "hw/i386/x86.h"
#endif
#include "disas/capstone.h"
@@ -8468,6 +8470,11 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
dc->user_creatable = true;
+#ifndef CONFIG_USER_ONLY
+ BusFinderClass *bfc = BUS_FINDER_CLASS(oc);
+ bfc->find_bus = x86_cpu_get_parent_bus;
+#endif
+
object_class_property_add(oc, "family", "int",
x86_cpuid_version_get_family,
x86_cpuid_version_set_family, NULL, NULL);
@@ -8520,6 +8527,10 @@ static const TypeInfo x86_cpu_type_info = {
.abstract = true,
.class_size = sizeof(X86CPUClass),
.class_init = x86_cpu_common_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_BUS_FINDER },
+ { }
+ }
};
/* "base" CPU model, used by query-cpu-model-expansion */
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [RFC v2 15/15] i386: Support topology device tree
2024-09-19 1:55 [RFC v2 00/15] qom-topo: Abstract CPU Topology Level to Topology Device Zhao Liu
` (13 preceding siblings ...)
2024-09-19 1:55 ` [RFC v2 14/15] i386/cpu: Support CPU plugged in topology tree via bus-finder Zhao Liu
@ 2024-09-19 1:55 ` Zhao Liu
14 siblings, 0 replies; 16+ messages in thread
From: Zhao Liu @ 2024-09-19 1:55 UTC (permalink / raw)
To: Daniel P . Berrangé, Igor Mammedov, Eduardo Habkost,
Marcel Apfelbaum, Philippe Mathieu-Daudé, Yanan Wang,
Michael S . Tsirkin, Paolo Bonzini, Richard Henderson,
Cédric Le Goater, Nicholas Piggin, Frédéric Barrat,
Daniel Henrique Barboza, David Gibson, Harsh Prateek Bora,
Markus Armbruster, Marcelo Tosatti, Alex Bennée,
Peter Maydell
Cc: qemu-devel, kvm, qemu-ppc, qemu-arm, Zhenyu Wang, Dapeng Mi,
Yongwei Ma, Zhao Liu
Support complete QOM CPu topology tree for x86 machine, and specify
bus_type for x86 CPU so that all x86 CPUs will be added in the topology
tree.
Since the CPU slot make the machine as the hotplug handler for all
topology devices, hotplug related hooks may used to handle other
topology devices besides the CPU. Thus, make microvm not assume that
the device is only a CPU when implementing the relevant hooks.
Additionally, drop code paths that are not needed by the topology tree
implementation.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
hw/i386/microvm.c | 13 +++++---
hw/i386/x86-common.c | 78 +++++---------------------------------------
hw/i386/x86.c | 2 ++
target/i386/cpu.c | 2 ++
4 files changed, 21 insertions(+), 74 deletions(-)
diff --git a/hw/i386/microvm.c b/hw/i386/microvm.c
index 40edcee7af29..49a897db50fc 100644
--- a/hw/i386/microvm.c
+++ b/hw/i386/microvm.c
@@ -417,16 +417,21 @@ static void microvm_fix_kernel_cmdline(MachineState *machine)
static void microvm_device_pre_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- X86CPU *cpu = X86_CPU(dev);
+ if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ X86CPU *cpu;
+ cpu = X86_CPU(dev);
- cpu->host_phys_bits = true; /* need reliable phys-bits */
- x86_cpu_pre_plug(hotplug_dev, dev, errp);
+ cpu->host_phys_bits = true; /* need reliable phys-bits */
+ x86_cpu_pre_plug(hotplug_dev, dev, errp);
+ }
}
static void microvm_device_plug_cb(HotplugHandler *hotplug_dev,
DeviceState *dev, Error **errp)
{
- x86_cpu_plug(hotplug_dev, dev, errp);
+ if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) {
+ x86_cpu_plug(hotplug_dev, dev, errp);
+ }
}
static void microvm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
diff --git a/hw/i386/x86-common.c b/hw/i386/x86-common.c
index d837aadc9dea..75d4b2f3d43a 100644
--- a/hw/i386/x86-common.c
+++ b/hw/i386/x86-common.c
@@ -129,26 +129,18 @@ static void x86_cpu_new(X86MachineState *x86ms, int index,
int64_t apic_id, Error **errp)
{
MachineState *ms = MACHINE(x86ms);
- MachineClass *mc = MACHINE_GET_CLASS(ms);
Object *cpu = object_new(ms->cpu_type);
DeviceState *dev = DEVICE(cpu);
BusState *bus = NULL;
+ X86CPUTopoIDs topo_ids;
+ X86CPUTopoInfo topo_info;
- /*
- * Once x86 machine supports topo_tree_supported, x86 CPU would
- * also have bus_type.
- */
- if (mc->smp_props.topo_tree_supported) {
- X86CPUTopoIDs topo_ids;
- X86CPUTopoInfo topo_info;
-
- init_topo_info(&topo_info, x86ms);
- x86_topo_ids_from_apicid(apic_id, &topo_info, &topo_ids);
- bus = x86_find_topo_bus(ms, &topo_ids);
+ init_topo_info(&topo_info, x86ms);
+ x86_topo_ids_from_apicid(apic_id, &topo_info, &topo_ids);
+ bus = x86_find_topo_bus(ms, &topo_ids);
- /* Only with dev->id, CPU can be inserted into topology tree. */
- dev->id = g_strdup_printf("%s[%d]", ms->cpu_type, index);
- }
+ /* Only with dev->id, CPU can be inserted into topology tree. */
+ dev->id = g_strdup_printf("%s[%d]", ms->cpu_type, index);
if (!object_property_set_uint(cpu, "apic-id", apic_id, errp)) {
goto out;
@@ -399,10 +391,7 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
X86CPU *cpu = X86_CPU(dev);
CPUX86State *env = &cpu->env;
MachineState *ms = MACHINE(hotplug_dev);
- MachineClass *mc = MACHINE_GET_CLASS(ms);
X86MachineState *x86ms = X86_MACHINE(hotplug_dev);
- unsigned int smp_cores = ms->smp.cores;
- unsigned int smp_threads = ms->smp.threads;
X86CPUTopoInfo topo_info;
if (!object_dynamic_cast(OBJECT(cpu), ms->cpu_type)) {
@@ -434,58 +423,7 @@ void x86_cpu_pre_plug(HotplugHandler *hotplug_dev,
set_bit(CPU_TOPOLOGY_LEVEL_DIE, env->avail_cpu_topo);
}
- if (cpu->apic_id == UNASSIGNED_APIC_ID &&
- !mc->smp_props.topo_tree_supported) {
- x86_fixup_topo_ids(ms, cpu);
-
- if (cpu->socket_id < 0) {
- error_setg(errp, "CPU socket-id is not set");
- return;
- } else if (cpu->socket_id > ms->smp.sockets - 1) {
- error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u",
- cpu->socket_id, ms->smp.sockets - 1);
- return;
- }
- if (cpu->die_id < 0) {
- error_setg(errp, "CPU die-id is not set");
- return;
- } else if (cpu->die_id > ms->smp.dies - 1) {
- error_setg(errp, "Invalid CPU die-id: %u must be in range 0:%u",
- cpu->die_id, ms->smp.dies - 1);
- }
- if (cpu->module_id < 0) {
- error_setg(errp, "CPU module-id is not set");
- return;
- } else if (cpu->module_id > ms->smp.modules - 1) {
- error_setg(errp, "Invalid CPU module-id: %u must be in range 0:%u",
- cpu->module_id, ms->smp.modules - 1);
- return;
- }
- if (cpu->core_id < 0) {
- error_setg(errp, "CPU core-id is not set");
- return;
- } else if (cpu->core_id > (smp_cores - 1)) {
- error_setg(errp, "Invalid CPU core-id: %u must be in range 0:%u",
- cpu->core_id, smp_cores - 1);
- return;
- }
- if (cpu->thread_id < 0) {
- error_setg(errp, "CPU thread-id is not set");
- return;
- } else if (cpu->thread_id > (smp_threads - 1)) {
- error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u",
- cpu->thread_id, smp_threads - 1);
- return;
- }
-
- topo_ids.pkg_id = cpu->socket_id;
- topo_ids.die_id = cpu->die_id;
- topo_ids.module_id = cpu->module_id;
- topo_ids.core_id = cpu->core_id;
- topo_ids.smt_id = cpu->thread_id;
- cpu->apic_id = x86_apicid_from_topo_ids(&topo_info, &topo_ids);
- } else if (cpu->apic_id == UNASSIGNED_APIC_ID &&
- mc->smp_props.topo_tree_supported) {
+ if (cpu->apic_id == UNASSIGNED_APIC_ID) {
/*
* For this case, CPU is added by specifying the bus. Under the
* topology tree, specifying only the bus should be feasible, but
diff --git a/hw/i386/x86.c b/hw/i386/x86.c
index 01fc5e656272..cdf7b81ad0e3 100644
--- a/hw/i386/x86.c
+++ b/hw/i386/x86.c
@@ -381,6 +381,8 @@ static void x86_machine_class_init(ObjectClass *oc, void *data)
mc->cpu_index_to_instance_props = x86_cpu_index_to_props;
mc->get_default_cpu_node_id = x86_get_default_cpu_node_id;
mc->possible_cpu_arch_ids = x86_possible_cpu_arch_ids;
+ mc->smp_props.arch_id_topo_level = CPU_TOPOLOGY_LEVEL_THREAD;
+ mc->smp_props.topo_tree_supported = true;
mc->kvm_type = x86_kvm_type;
x86mc->save_tsc_khz = true;
x86mc->fwcfg_dma_enabled = true;
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index 90221ceb7313..fb54c2c100a0 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -8473,6 +8473,8 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
#ifndef CONFIG_USER_ONLY
BusFinderClass *bfc = BUS_FINDER_CLASS(oc);
bfc->find_bus = x86_cpu_get_parent_bus;
+
+ dc->bus_type = TYPE_CPU_BUS;
#endif
object_class_property_add(oc, "family", "int",
--
2.34.1
^ permalink raw reply related [flat|nested] 16+ messages in thread