]> Git Repo - qemu.git/blobdiff - hw/core/machine.c
Revert "machine: Convert abstract typename on compat_props to subclass names"
[qemu.git] / hw / core / machine.c
index afd84accbf21a141fb807823631510a9f0d1219d..41b53a17ad3220d1b3b3b28a79f8fe673cc2193e 100644 (file)
 #include "qapi/visitor.h"
 #include "hw/sysbus.h"
 #include "sysemu/sysemu.h"
+#include "sysemu/numa.h"
 #include "qemu/error-report.h"
 #include "qemu/cutils.h"
+#include "sysemu/numa.h"
+#include "sysemu/qtest.h"
 
 static char *machine_get_accel(Object *obj, Error **errp)
 {
@@ -357,6 +360,133 @@ static void machine_init_notify(Notifier *notifier, void *data)
     foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL);
 }
 
+HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine)
+{
+    int i;
+    Object *cpu;
+    HotpluggableCPUList *head = NULL;
+    const char *cpu_type;
+
+    cpu = machine->possible_cpus->cpus[0].cpu;
+    assert(cpu); /* Boot cpu is always present */
+    cpu_type = object_get_typename(cpu);
+    for (i = 0; i < machine->possible_cpus->len; i++) {
+        HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1);
+        HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1);
+
+        cpu_item->type = g_strdup(cpu_type);
+        cpu_item->vcpus_count = machine->possible_cpus->cpus[i].vcpus_count;
+        cpu_item->props = g_memdup(&machine->possible_cpus->cpus[i].props,
+                                   sizeof(*cpu_item->props));
+
+        cpu = machine->possible_cpus->cpus[i].cpu;
+        if (cpu) {
+            cpu_item->has_qom_path = true;
+            cpu_item->qom_path = object_get_canonical_path(cpu);
+        }
+        list_item->value = cpu_item;
+        list_item->next = head;
+        head = list_item;
+    }
+    return head;
+}
+
+/**
+ * machine_set_cpu_numa_node:
+ * @machine: machine object to modify
+ * @props: specifies which cpu objects to assign to
+ *         numa node specified by @props.node_id
+ * @errp: if an error occurs, a pointer to an area to store the error
+ *
+ * Associate NUMA node specified by @props.node_id with cpu slots that
+ * match socket/core/thread-ids specified by @props. It's recommended to use
+ * query-hotpluggable-cpus.props values to specify affected cpu slots,
+ * which would lead to exact 1:1 mapping of cpu slots to NUMA node.
+ *
+ * However for CLI convenience it's possible to pass in subset of properties,
+ * which would affect all cpu slots that match it.
+ * Ex for pc machine:
+ *    -smp 4,cores=2,sockets=2 -numa node,nodeid=0 -numa node,nodeid=1 \
+ *    -numa cpu,node-id=0,socket_id=0 \
+ *    -numa cpu,node-id=1,socket_id=1
+ * will assign all child cores of socket 0 to node 0 and
+ * of socket 1 to node 1.
+ *
+ * On attempt of reassigning (already assigned) cpu slot to another NUMA node,
+ * return error.
+ * Empty subset is disallowed and function will return with error in this case.
+ */
+void machine_set_cpu_numa_node(MachineState *machine,
+                               const CpuInstanceProperties *props, Error **errp)
+{
+    MachineClass *mc = MACHINE_GET_CLASS(machine);
+    bool match = false;
+    int i;
+
+    if (!mc->possible_cpu_arch_ids) {
+        error_setg(errp, "mapping of CPUs to NUMA node is not supported");
+        return;
+    }
+
+    /* disabling node mapping is not supported, forbid it */
+    assert(props->has_node_id);
+
+    /* force board to initialize possible_cpus if it hasn't been done yet */
+    mc->possible_cpu_arch_ids(machine);
+
+    for (i = 0; i < machine->possible_cpus->len; i++) {
+        CPUArchId *slot = &machine->possible_cpus->cpus[i];
+
+        /* reject unsupported by board properties */
+        if (props->has_thread_id && !slot->props.has_thread_id) {
+            error_setg(errp, "thread-id is not supported");
+            return;
+        }
+
+        if (props->has_core_id && !slot->props.has_core_id) {
+            error_setg(errp, "core-id is not supported");
+            return;
+        }
+
+        if (props->has_socket_id && !slot->props.has_socket_id) {
+            error_setg(errp, "socket-id is not supported");
+            return;
+        }
+
+        /* skip slots with explicit mismatch */
+        if (props->has_thread_id && props->thread_id != slot->props.thread_id) {
+                continue;
+        }
+
+        if (props->has_core_id && props->core_id != slot->props.core_id) {
+                continue;
+        }
+
+        if (props->has_socket_id && props->socket_id != slot->props.socket_id) {
+                continue;
+        }
+
+        /* reject assignment if slot is already assigned, for compatibility
+         * of legacy cpu_index mapping with SPAPR core based mapping do not
+         * error out if cpu thread and matched core have the same node-id */
+        if (slot->props.has_node_id &&
+            slot->props.node_id != props->node_id) {
+            error_setg(errp, "CPU is already assigned to node-id: %" PRId64,
+                       slot->props.node_id);
+            return;
+        }
+
+        /* assign slot to node as it's matched '-numa cpu' key */
+        match = true;
+        slot->props.node_id = props->node_id;
+        slot->props.has_node_id = props->has_node_id;
+    }
+
+    if (!match) {
+        error_setg(errp, "no match found");
+    }
+}
+
 static void machine_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
@@ -364,6 +494,110 @@ static void machine_class_init(ObjectClass *oc, void *data)
     /* Default 128 MB as guest ram size */
     mc->default_ram_size = 128 * M_BYTE;
     mc->rom_file_has_mr = true;
+
+    /* numa node memory size aligned on 8MB by default.
+     * On Linux, each node's border has to be 8MB aligned
+     */
+    mc->numa_mem_align_shift = 23;
+    mc->numa_auto_assign_ram = numa_default_auto_assign_ram;
+
+    object_class_property_add_str(oc, "accel",
+        machine_get_accel, machine_set_accel, &error_abort);
+    object_class_property_set_description(oc, "accel",
+        "Accelerator list", &error_abort);
+
+    object_class_property_add(oc, "kernel-irqchip", "OnOffSplit",
+        NULL, machine_set_kernel_irqchip,
+        NULL, NULL, &error_abort);
+    object_class_property_set_description(oc, "kernel-irqchip",
+        "Configure KVM in-kernel irqchip", &error_abort);
+
+    object_class_property_add(oc, "kvm-shadow-mem", "int",
+        machine_get_kvm_shadow_mem, machine_set_kvm_shadow_mem,
+        NULL, NULL, &error_abort);
+    object_class_property_set_description(oc, "kvm-shadow-mem",
+        "KVM shadow MMU size", &error_abort);
+
+    object_class_property_add_str(oc, "kernel",
+        machine_get_kernel, machine_set_kernel, &error_abort);
+    object_class_property_set_description(oc, "kernel",
+        "Linux kernel image file", &error_abort);
+
+    object_class_property_add_str(oc, "initrd",
+        machine_get_initrd, machine_set_initrd, &error_abort);
+    object_class_property_set_description(oc, "initrd",
+        "Linux initial ramdisk file", &error_abort);
+
+    object_class_property_add_str(oc, "append",
+        machine_get_append, machine_set_append, &error_abort);
+    object_class_property_set_description(oc, "append",
+        "Linux kernel command line", &error_abort);
+
+    object_class_property_add_str(oc, "dtb",
+        machine_get_dtb, machine_set_dtb, &error_abort);
+    object_class_property_set_description(oc, "dtb",
+        "Linux kernel device tree file", &error_abort);
+
+    object_class_property_add_str(oc, "dumpdtb",
+        machine_get_dumpdtb, machine_set_dumpdtb, &error_abort);
+    object_class_property_set_description(oc, "dumpdtb",
+        "Dump current dtb to a file and quit", &error_abort);
+
+    object_class_property_add(oc, "phandle-start", "int",
+        machine_get_phandle_start, machine_set_phandle_start,
+        NULL, NULL, &error_abort);
+    object_class_property_set_description(oc, "phandle-start",
+            "The first phandle ID we may generate dynamically", &error_abort);
+
+    object_class_property_add_str(oc, "dt-compatible",
+        machine_get_dt_compatible, machine_set_dt_compatible, &error_abort);
+    object_class_property_set_description(oc, "dt-compatible",
+        "Overrides the \"compatible\" property of the dt root node",
+        &error_abort);
+
+    object_class_property_add_bool(oc, "dump-guest-core",
+        machine_get_dump_guest_core, machine_set_dump_guest_core, &error_abort);
+    object_class_property_set_description(oc, "dump-guest-core",
+        "Include guest memory in  a core dump", &error_abort);
+
+    object_class_property_add_bool(oc, "mem-merge",
+        machine_get_mem_merge, machine_set_mem_merge, &error_abort);
+    object_class_property_set_description(oc, "mem-merge",
+        "Enable/disable memory merge support", &error_abort);
+
+    object_class_property_add_bool(oc, "usb",
+        machine_get_usb, machine_set_usb, &error_abort);
+    object_class_property_set_description(oc, "usb",
+        "Set on/off to enable/disable usb", &error_abort);
+
+    object_class_property_add_bool(oc, "graphics",
+        machine_get_graphics, machine_set_graphics, &error_abort);
+    object_class_property_set_description(oc, "graphics",
+        "Set on/off to enable/disable graphics emulation", &error_abort);
+
+    object_class_property_add_bool(oc, "igd-passthru",
+        machine_get_igd_gfx_passthru, machine_set_igd_gfx_passthru,
+        &error_abort);
+    object_class_property_set_description(oc, "igd-passthru",
+        "Set on/off to enable/disable igd passthrou", &error_abort);
+
+    object_class_property_add_str(oc, "firmware",
+        machine_get_firmware, machine_set_firmware,
+        &error_abort);
+    object_class_property_set_description(oc, "firmware",
+        "Firmware image", &error_abort);
+
+    object_class_property_add_bool(oc, "suppress-vmdesc",
+        machine_get_suppress_vmdesc, machine_set_suppress_vmdesc,
+        &error_abort);
+    object_class_property_set_description(oc, "suppress-vmdesc",
+        "Set on to disable self-describing migration", &error_abort);
+
+    object_class_property_add_bool(oc, "enforce-config-section",
+        machine_get_enforce_config_section, machine_set_enforce_config_section,
+        &error_abort);
+    object_class_property_set_description(oc, "enforce-config-section",
+        "Set on to enforce configuration section migration", &error_abort);
 }
 
 static void machine_class_base_init(ObjectClass *oc, void *data)
@@ -387,114 +621,6 @@ static void machine_initfn(Object *obj)
     ms->mem_merge = true;
     ms->enable_graphics = true;
 
-    object_property_add_str(obj, "accel",
-                            machine_get_accel, machine_set_accel, NULL);
-    object_property_set_description(obj, "accel",
-                                    "Accelerator list",
-                                    NULL);
-    object_property_add(obj, "kernel-irqchip", "OnOffSplit",
-                        NULL,
-                        machine_set_kernel_irqchip,
-                        NULL, NULL, NULL);
-    object_property_set_description(obj, "kernel-irqchip",
-                                    "Configure KVM in-kernel irqchip",
-                                    NULL);
-    object_property_add(obj, "kvm-shadow-mem", "int",
-                        machine_get_kvm_shadow_mem,
-                        machine_set_kvm_shadow_mem,
-                        NULL, NULL, NULL);
-    object_property_set_description(obj, "kvm-shadow-mem",
-                                    "KVM shadow MMU size",
-                                    NULL);
-    object_property_add_str(obj, "kernel",
-                            machine_get_kernel, machine_set_kernel, NULL);
-    object_property_set_description(obj, "kernel",
-                                    "Linux kernel image file",
-                                    NULL);
-    object_property_add_str(obj, "initrd",
-                            machine_get_initrd, machine_set_initrd, NULL);
-    object_property_set_description(obj, "initrd",
-                                    "Linux initial ramdisk file",
-                                    NULL);
-    object_property_add_str(obj, "append",
-                            machine_get_append, machine_set_append, NULL);
-    object_property_set_description(obj, "append",
-                                    "Linux kernel command line",
-                                    NULL);
-    object_property_add_str(obj, "dtb",
-                            machine_get_dtb, machine_set_dtb, NULL);
-    object_property_set_description(obj, "dtb",
-                                    "Linux kernel device tree file",
-                                    NULL);
-    object_property_add_str(obj, "dumpdtb",
-                            machine_get_dumpdtb, machine_set_dumpdtb, NULL);
-    object_property_set_description(obj, "dumpdtb",
-                                    "Dump current dtb to a file and quit",
-                                    NULL);
-    object_property_add(obj, "phandle-start", "int",
-                        machine_get_phandle_start,
-                        machine_set_phandle_start,
-                        NULL, NULL, NULL);
-    object_property_set_description(obj, "phandle-start",
-                                    "The first phandle ID we may generate dynamically",
-                                    NULL);
-    object_property_add_str(obj, "dt-compatible",
-                            machine_get_dt_compatible,
-                            machine_set_dt_compatible,
-                            NULL);
-    object_property_set_description(obj, "dt-compatible",
-                                    "Overrides the \"compatible\" property of the dt root node",
-                                    NULL);
-    object_property_add_bool(obj, "dump-guest-core",
-                             machine_get_dump_guest_core,
-                             machine_set_dump_guest_core,
-                             NULL);
-    object_property_set_description(obj, "dump-guest-core",
-                                    "Include guest memory in  a core dump",
-                                    NULL);
-    object_property_add_bool(obj, "mem-merge",
-                             machine_get_mem_merge,
-                             machine_set_mem_merge, NULL);
-    object_property_set_description(obj, "mem-merge",
-                                    "Enable/disable memory merge support",
-                                    NULL);
-    object_property_add_bool(obj, "usb",
-                             machine_get_usb,
-                             machine_set_usb, NULL);
-    object_property_set_description(obj, "usb",
-                                    "Set on/off to enable/disable usb",
-                                    NULL);
-    object_property_add_bool(obj, "graphics",
-                             machine_get_graphics,
-                             machine_set_graphics, NULL);
-    object_property_set_description(obj, "graphics",
-                                    "Set on/off to enable/disable graphics emulation",
-                                    NULL);
-    object_property_add_bool(obj, "igd-passthru",
-                             machine_get_igd_gfx_passthru,
-                             machine_set_igd_gfx_passthru, NULL);
-    object_property_set_description(obj, "igd-passthru",
-                                    "Set on/off to enable/disable igd passthrou",
-                                    NULL);
-    object_property_add_str(obj, "firmware",
-                            machine_get_firmware,
-                            machine_set_firmware, NULL);
-    object_property_set_description(obj, "firmware",
-                                    "Firmware image",
-                                    NULL);
-    object_property_add_bool(obj, "suppress-vmdesc",
-                             machine_get_suppress_vmdesc,
-                             machine_set_suppress_vmdesc, NULL);
-    object_property_set_description(obj, "suppress-vmdesc",
-                                    "Set on to disable self-describing migration",
-                                    NULL);
-    object_property_add_bool(obj, "enforce-config-section",
-                             machine_get_enforce_config_section,
-                             machine_set_enforce_config_section, NULL);
-    object_property_set_description(obj, "enforce-config-section",
-                                    "Set on to enforce configuration section migration",
-                                    NULL);
-
     /* Register notifier when init is done for sysbus sanity checks */
     ms->sysbus_notifier.notify = machine_init_notify;
     qemu_add_machine_init_done_notifier(&ms->sysbus_notifier);
@@ -554,6 +680,86 @@ bool machine_mem_merge(MachineState *machine)
     return machine->mem_merge;
 }
 
+static char *cpu_slot_to_string(const CPUArchId *cpu)
+{
+    GString *s = g_string_new(NULL);
+    if (cpu->props.has_socket_id) {
+        g_string_append_printf(s, "socket-id: %"PRId64, cpu->props.socket_id);
+    }
+    if (cpu->props.has_core_id) {
+        if (s->len) {
+            g_string_append_printf(s, ", ");
+        }
+        g_string_append_printf(s, "core-id: %"PRId64, cpu->props.core_id);
+    }
+    if (cpu->props.has_thread_id) {
+        if (s->len) {
+            g_string_append_printf(s, ", ");
+        }
+        g_string_append_printf(s, "thread-id: %"PRId64, cpu->props.thread_id);
+    }
+    return g_string_free(s, false);
+}
+
+static void machine_numa_finish_init(MachineState *machine)
+{
+    int i;
+    bool default_mapping;
+    GString *s = g_string_new(NULL);
+    MachineClass *mc = MACHINE_GET_CLASS(machine);
+    const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(machine);
+
+    assert(nb_numa_nodes);
+    for (i = 0; i < possible_cpus->len; i++) {
+        if (possible_cpus->cpus[i].props.has_node_id) {
+            break;
+        }
+    }
+    default_mapping = (i == possible_cpus->len);
+
+    for (i = 0; i < possible_cpus->len; i++) {
+        const CPUArchId *cpu_slot = &possible_cpus->cpus[i];
+
+        if (!cpu_slot->props.has_node_id) {
+            /* fetch default mapping from board and enable it */
+            CpuInstanceProperties props = cpu_slot->props;
+
+            if (!default_mapping) {
+                /* record slots with not set mapping,
+                 * TODO: make it hard error in future */
+                char *cpu_str = cpu_slot_to_string(cpu_slot);
+                g_string_append_printf(s, "%sCPU %d [%s]",
+                                       s->len ? ", " : "", i, cpu_str);
+                g_free(cpu_str);
+
+                /* non mapped cpus used to fallback to node 0 */
+                props.node_id = 0;
+            }
+
+            props.has_node_id = true;
+            machine_set_cpu_numa_node(machine, &props, &error_fatal);
+        }
+    }
+    if (s->len && !qtest_enabled()) {
+        warn_report("CPU(s) not present in any NUMA nodes: %s",
+                    s->str);
+        warn_report("All CPU(s) up to maxcpus should be described "
+                    "in NUMA config, ability to start up with partial NUMA "
+                    "mappings is obsoleted and will be removed in future");
+    }
+    g_string_free(s, true);
+}
+
+void machine_run_board_init(MachineState *machine)
+{
+    MachineClass *machine_class = MACHINE_GET_CLASS(machine);
+
+    if (nb_numa_nodes) {
+        machine_numa_finish_init(machine);
+    }
+    machine_class->init(machine);
+}
+
 static void machine_class_finalize(ObjectClass *klass, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(klass);
This page took 0.034605 seconds and 4 git commands to generate.