@@ -3953,7 +3953,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:
@@ -4045,7 +4045,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);
@@ -195,6 +195,16 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cpu = CPU(dev);
Object *machine = qdev_get_machine();
+ CPUClass *cc = CPU_GET_CLASS(cpu);
+
+ /*
+ * The parent topology realize() must be completed before cpu_resume()
+ * where the CPU starts to run.
+ */
+ 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
@@ -225,6 +235,7 @@ static void cpu_common_realizefn(DeviceState *dev, Error **errp)
static void cpu_common_unrealizefn(DeviceState *dev)
{
CPUState *cpu = CPU(dev);
+ CPUClass *cc = CPU_GET_CLASS(cpu);
/* Call the plugin hook before clearing the cpu is fully unrealized */
if (tcg_enabled()) {
@@ -233,6 +244,7 @@ static void cpu_common_unrealizefn(DeviceState *dev)
/* NOTE: latest generic point before the cpu is fully unrealized */
cpu_exec_unrealizefn(cpu);
+ cc->parent_unrealize(dev);
}
static void cpu_common_initfn(Object *obj)
@@ -275,6 +287,7 @@ static void cpu_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;
@@ -282,9 +295,6 @@ static void cpu_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);
/*
@@ -292,11 +302,18 @@ static void cpu_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. */
+ dc->hotpluggable = true;
+ device_class_set_parent_realize(dc, cpu_common_realizefn,
+ &k->parent_realize);
+ device_class_set_parent_unrealize(dc, cpu_common_unrealizefn,
+ &k->parent_unrealize);
+ tc->level = CPU_TOPO_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,
@@ -20,6 +20,7 @@
#ifndef QEMU_CPU_H
#define QEMU_CPU_H
+#include "hw/core/cpu-topo.h"
#include "hw/qdev-core.h"
#include "disas/dis-asm.h"
#include "exec/cpu-common.h"
@@ -146,7 +147,7 @@ struct SysemuCPUOps;
*/
struct CPUClass {
/*< private >*/
- DeviceClass parent_class;
+ CPUTopoClass parent_class;
/*< public >*/
ObjectClass *(*class_by_name)(const char *cpu_model);
@@ -191,6 +192,9 @@ struct CPUClass {
int reset_dump_flags;
int gdb_num_core_regs;
bool gdb_stop_before_watchpoint;
+
+ DeviceRealize parent_realize;
+ DeviceUnrealize parent_unrealize;
};
/*
@@ -456,7 +460,7 @@ struct qemu_work_item;
*/
struct CPUState {
/*< private >*/
- DeviceState parent_obj;
+ CPUTopoState parent_obj;
/* cache to avoid expensive CPU_GET_CLASS */
CPUClass *cc;
/*< public >*/