qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC] QMP: add query-hotpluggable-cpus


From: Igor Mammedov
Subject: [Qemu-devel] [RFC] QMP: add query-hotpluggable-cpus
Date: Mon, 15 Feb 2016 18:10:28 +0100

it will allow mgmt to query present and possible to hotplug CPUs
it is required from a target platform that wish to support
command to set board specific MachineClass.possible_cpus() hook,
which will return a list of possible CPUs with options
that would be needed for hotplugging possible CPUs.

For RFC there are:
   'arch_id': 'int' - mandatory unique CPU number,
                      for x86 it's APIC ID for ARM it's MPIDR
   'type': 'str' - CPU object type for usage with device_add

and a set of optional fields that would allows mgmt tools
to know at what granularity and where a new CPU could be
hotplugged;
[node],[socket],[core],[thread]
Hopefully that should cover needs for CPU hotplug porposes for
magor targets and we can extend structure in future adding
more fields if it will be needed.

also for present CPUs there is a 'cpu_link' field which
would allow mgmt inspect whatever object/abstraction
the target platform considers as CPU object.

For RFC purposes implements only for x86 target so far.

Signed-off-by: Igor Mammedov <address@hidden>
---
 hw/i386/pc.c               | 59 ++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/boards.h        |  6 +++++
 include/hw/i386/topology.h | 15 ++++++++++++
 monitor.c                  | 13 ++++++++++
 qapi-schema.json           | 30 +++++++++++++++++++++++
 qmp-commands.hx            | 26 ++++++++++++++++++++
 target-i386/cpu.c          |  2 +-
 target-i386/cpu.h          |  1 +
 8 files changed, 151 insertions(+), 1 deletion(-)

diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 87660cd..d5f1c52 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1931,6 +1931,64 @@ static unsigned pc_cpu_index_to_socket_id(unsigned 
cpu_index)
     return topo.pkg_id;
 }
 
+static void pc_add_possible_cpu_descriptor(HotpluggableCPUList **head,
+                                           const char *model_name,
+                                           uint32_t apic_id,
+                                           char *cpu_link)
+{
+    X86CPUTopoInfo topo;
+    HotpluggableCPUList *list_item = g_new0(HotpluggableCPUList, 1);
+    HotpluggableCPU *cpu_item = g_new0(HotpluggableCPU, 1);
+
+    cpu_item->type = x86_cpu_type_name(model_name);
+    cpu_item->arch_id = apic_id;
+    x86_topo_ids_from_apicid(apic_id, smp_cores, smp_threads, &topo);
+    cpu_item->has_socket = true;
+    cpu_item->socket = topo.pkg_id;
+    cpu_item->has_core = true;
+    cpu_item->core = topo.core_id;
+    cpu_item->has_thread = true;
+    cpu_item->thread = topo.smt_id;
+    cpu_item->has_cpu_link = cpu_link;
+    cpu_item->cpu_link = cpu_link;
+
+    list_item->value = cpu_item;
+    list_item->next = *head;
+    *head = list_item;
+}
+
+static HotpluggableCPUList *pc_possible_cpus(MachineState *machine)
+{
+    int i;
+    CPUState *cpu;
+    uint32_t apic_id;
+    gchar **model_pieces;
+    HotpluggableCPUList *head = NULL;
+    DECLARE_BITMAP(found_cpus, ACPI_CPU_HOTPLUG_ID_LIMIT);
+
+    model_pieces = g_strsplit(machine->cpu_model, ",", 2);
+
+    memset(found_cpus, 0, sizeof found_cpus);
+    CPU_FOREACH(cpu) {
+        CPUClass *cc = CPU_GET_CLASS(cpu);
+
+        apic_id = cc->get_arch_id(cpu);
+        set_bit(apic_id, found_cpus);
+        pc_add_possible_cpu_descriptor(&head, model_pieces[0], apic_id,
+                                       object_get_canonical_path(OBJECT(cpu)));
+    }
+
+
+    for (i = 0; i < max_cpus; i++) {
+        apic_id = x86_cpu_apic_id_from_index(i);
+        if (!test_bit(apic_id, found_cpus)) {
+            pc_add_possible_cpu_descriptor(&head, model_pieces[0], apic_id,
+                                           NULL);
+        }
+    }
+    return head;
+}
+
 static void pc_machine_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
@@ -1953,6 +2011,7 @@ static void pc_machine_class_init(ObjectClass *oc, void 
*data)
     pcmc->save_tsc_khz = true;
     mc->get_hotplug_handler = pc_get_hotpug_handler;
     mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id;
+    mc->possible_cpus = pc_possible_cpus;
     mc->default_boot_order = "cad";
     mc->hot_add_cpu = pc_hot_add_cpu;
     mc->max_cpus = 255;
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 0f30959..0a29cad 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -57,6 +57,11 @@ bool machine_mem_merge(MachineState *machine);
  *    Set only by old machines because they need to keep
  *    compatibility on code that exposed QEMU_VERSION to guests in
  *    the past (and now use qemu_hw_version()).
+ * @possible_cpus:
+ *    Returns a list of @HotpluggableCPU descriptors
+ *    which includes CPU IDs for present and possible to hotplug CPUs
+ *    and coresponding type an topology information.
+ *    Caller is responsible for freeing returned list.
  */
 struct MachineClass {
     /*< private >*/
@@ -99,6 +104,7 @@ struct MachineClass {
     HotplugHandler *(*get_hotplug_handler)(MachineState *machine,
                                            DeviceState *dev);
     unsigned (*cpu_index_to_socket_id)(unsigned cpu_index);
+    HotpluggableCPUList *(*possible_cpus)(MachineState *machine);
 };
 
 /**
diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h
index 148cc1b..9e9c00c 100644
--- a/include/hw/i386/topology.h
+++ b/include/hw/i386/topology.h
@@ -119,6 +119,21 @@ static inline void x86_topo_ids_from_idx(unsigned nr_cores,
     topo->pkg_id = core_index / nr_cores;
 }
 
+/* Calculate thread/core/package IDs for a specific topology,
+ * based on APIC ID
+ */
+static inline void x86_topo_ids_from_apicid(unsigned apicid,
+                                            unsigned nr_cores,
+                                            unsigned nr_threads,
+                                            X86CPUTopoInfo *topo)
+{
+    topo->smt_id = apicid &
+                   ~(0xFFFFFFFFUL << apicid_smt_width(nr_cores, nr_threads));
+    topo->core_id = (apicid >> apicid_core_offset(nr_cores, nr_threads)) &
+                   ~(0xFFFFFFFFUL << apicid_core_width(nr_cores, nr_threads));
+    topo->pkg_id = apicid >> apicid_pkg_offset(nr_cores, nr_threads);
+}
+
 /* Make APIC ID for the CPU 'cpu_index'
  *
  * 'cpu_index' is a sequential, contiguous ID for the CPU.
diff --git a/monitor.c b/monitor.c
index 73eac17..0c9e6ce 100644
--- a/monitor.c
+++ b/monitor.c
@@ -4241,3 +4241,16 @@ void qmp_dump_skeys(const char *filename, Error **errp)
     error_setg(errp, QERR_FEATURE_DISABLED, "dump-skeys");
 }
 #endif
+
+HotpluggableCPUList *qmp_query_hotpluggable_cpus(Error **errp)
+{
+    MachineState *ms = MACHINE(qdev_get_machine());
+    MachineClass *mc = MACHINE_GET_CLASS(ms);
+
+    if (!mc->possible_cpus) {
+        error_setg(errp, QERR_FEATURE_DISABLED, "query-hotpluggable-cpus");
+        return NULL;
+    }
+
+    return mc->possible_cpus(ms);
+}
diff --git a/qapi-schema.json b/qapi-schema.json
index 8d04897..127ba51 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4083,3 +4083,33 @@
 ##
 { 'enum': 'ReplayMode',
   'data': [ 'none', 'record', 'play' ] }
+
+##
+# @HotpluggableCPU
+#
+# @type: CPU object tyep for usage with device_add command
+# @arch_id: unique number designating the CPU within board
+# @node: NUMA node ID the CPU belongs to, optional
+# @socket: socket number within node/board the CPU belongs to, optional
+# @core: core number within socket the CPU belongs to, optional
+# @thread: thread number within core the CPU belongs to, optional
+# @cpu_link: link to existing CPU object is CPU is present or
+#            omitted if CPU is not present.
+#
+# Since: 2.6
+{ 'struct': 'HotpluggableCPU',
+  'data': { 'type': 'str',
+            'arch_id': 'int',
+            '*node': 'int',
+            '*socket': 'int',
+            '*core': 'int',
+            '*thread': 'int',
+            '*cpu_link': 'str'
+          }
+}
+
+##
+# @query-hotpluggable-cpus
+#
+# Since: 2.6
+{ 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'] }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 020e5ee..cbe0ba4 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4818,3 +4818,29 @@ Example:
                  {"type": 0, "out-pport": 0, "pport": 0, "vlan-id": 3840,
                   "pop-vlan": 1, "id": 251658240}
    ]}
+
+EQMP
+
+    {
+        .name       = "query-hotpluggable-cpus",
+        .args_type  = "",
+        .mhandler.cmd_new = qmp_marshal_query_hotpluggable_cpus,
+    },
+
+SQMP
+Show  existing/possible CPUs
+-------------------------------
+
+Arguments: None.
+
+Example for x86 target started with -smp 
2,sockets=2,cores=1,threads=3,maxcpus=6:
+
+-> { "execute": "query-hotpluggable-cpus" }
+<- {"return": [
+     {"core": 0, "socket": 1, "thread": 2, "arch_id": 6, "type": 
"qemu64-x86_64-cpu"},
+     {"core": 0, "socket": 1, "thread": 1, "arch_id": 5, "type": 
"qemu64-x86_64-cpu"},
+     {"core": 0, "socket": 1, "thread": 0, "arch_id": 4, "type": 
"qemu64-x86_64-cpu"},
+     {"core": 0, "socket": 0, "thread": 2, "arch_id": 2, "type": 
"qemu64-x86_64-cpu"},
+     {"core": 0, "arch_id": 1, "socket": 0, "thread": 1, "type": 
"qemu64-x86_64-cpu", "cpu_link": "/machine/unattached/device[3]"},
+     {"core": 0, "arch_id": 0, "socket": 0, "thread": 0, "type": 
"qemu64-x86_64-cpu", "cpu_link": "/machine/unattached/device[0]"}
+   ]}'
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 3918f01..c9b33b8 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -647,7 +647,7 @@ static void add_flagname_to_bitmaps(const char *flagname,
 /* Return type name for a given CPU model name
  * Caller is responsible for freeing the returned string.
  */
-static char *x86_cpu_type_name(const char *model_name)
+char *x86_cpu_type_name(const char *model_name)
 {
     return g_strdup_printf(X86_CPU_TYPE_NAME("%s"), model_name);
 }
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index a990ea7..84e8183 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -1354,4 +1354,5 @@ void enable_compat_apic_id_mode(void);
 void x86_cpu_dump_local_apic_state(CPUState *cs, FILE *f,
                                    fprintf_function cpu_fprintf, int flags);
 
+char *x86_cpu_type_name(const char *model_name);
 #endif /* CPU_I386_H */
-- 
1.8.3.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]