Commit ba9915e1 authored by Stefan Hajnoczi's avatar Stefan Hajnoczi
Browse files

Merge remote-tracking branch 'ehabkost/tags/x86-and-machine-pull-request' into staging



x86 and machine queue, 2017-05-11

Highlights:
* New "-numa cpu" option
* NUMA distance configuration
* migration/i386 vmstatification

# gpg: Signature made Thu 11 May 2017 08:16:07 PM BST
# gpg:                using RSA key 0x2807936F984DC5A6
# gpg: Good signature from "Eduardo Habkost <ehabkost@redhat.com>"
# gpg: Note: This key has expired!
# Primary key fingerprint: 5A32 2FD5 ABC4 D3DB ACCF  D1AA 2807 936F 984D C5A6

* ehabkost/tags/x86-and-machine-pull-request: (29 commits)
  migration/i386: Remove support for pre-0.12 formats
  vmstatification: i386 FPReg
  migration/i386: Remove old non-softfloat 64bit FP support
  tests: check -numa node,cpu=props_list usecase
  numa: add '-numa cpu,...' option for property based node mapping
  numa: remove node_cpu bitmaps as they are no longer used
  numa: use possible_cpus for not mapped CPUs check
  machine: call machine init from wrapper
  numa: remove no longer need numa_post_machine_init()
  tests: numa: add case for QMP command query-cpus
  QMP: include CpuInstanceProperties into query_cpus output output
  virt-arm: get numa node mapping from possible_cpus instead of numa_get_node_for_cpu()
  spapr: get numa node mapping from possible_cpus instead of numa_get_node_for_cpu()
  pc: get numa node mapping from possible_cpus instead of numa_get_node_for_cpu()
  numa: do default mapping based on possible_cpus instead of node_cpu bitmaps
  numa: mirror cpu to node mapping in MachineState::possible_cpus
  numa: add check that board supports cpu_index to node mapping
  virt-arm: add node-id property to CPU
  pc: add node-id property to CPU
  spapr: add node-id property to sPAPR core
  ...

Signed-off-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
parents 43ad494c 08b277ac
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@
#include "qapi-event.h"
#include "hw/nmi.h"
#include "sysemu/replay.h"
#include "hw/boards.h"

#ifdef CONFIG_LINUX

@@ -1865,6 +1866,8 @@ void list_cpus(FILE *f, fprintf_function cpu_fprintf, const char *optarg)

CpuInfoList *qmp_query_cpus(Error **errp)
{
    MachineState *ms = MACHINE(qdev_get_machine());
    MachineClass *mc = MACHINE_GET_CLASS(ms);
    CpuInfoList *head = NULL, *cur_item = NULL;
    CPUState *cpu;

@@ -1915,6 +1918,13 @@ CpuInfoList *qmp_query_cpus(Error **errp)
#else
        info->value->arch = CPU_INFO_ARCH_OTHER;
#endif
        info->value->has_props = !!mc->cpu_index_to_instance_props;
        if (info->value->has_props) {
            CpuInstanceProperties *props;
            props = g_malloc0(sizeof(*props));
            *props = mc->cpu_index_to_instance_props(ms, cpu->cpu_index);
            info->value->props = props;
        }

        /* XXX: waiting for the qapi to support GSList */
        if (!cur_item) {
+26 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include "hw/acpi/aml-build.h"
#include "qemu/bswap.h"
#include "qemu/bitops.h"
#include "sysemu/numa.h"

static GArray *build_alloc_array(void)
{
@@ -1609,3 +1610,28 @@ void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
    numamem->base_addr = cpu_to_le64(base);
    numamem->range_length = cpu_to_le64(len);
}

/*
 * ACPI spec 5.2.17 System Locality Distance Information Table
 * (Revision 2.0 or later)
 */
void build_slit(GArray *table_data, BIOSLinker *linker)
{
    int slit_start, i, j;
    slit_start = table_data->len;

    acpi_data_push(table_data, sizeof(AcpiTableHeader));

    build_append_int_noprefix(table_data, nb_numa_nodes, 8);
    for (i = 0; i < nb_numa_nodes; i++) {
        for (j = 0; j < nb_numa_nodes; j++) {
            assert(numa_info[i].distance[j]);
            build_append_int_noprefix(table_data, numa_info[i].distance[j], 1);
        }
    }

    build_header(linker, table_data,
                 (void *)(table_data->data + slit_start),
                 "SLIT",
                 table_data->len - slit_start, 1, NULL, NULL);
}
+3 −4
Original line number Diff line number Diff line
@@ -503,7 +503,6 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,

        /* build Processor object for each processor */
        for (i = 0; i < arch_ids->len; i++) {
            int j;
            Aml *dev;
            Aml *uid = aml_int(i);
            GArray *madt_buf = g_array_new(0, 1, 1);
@@ -557,9 +556,9 @@ void build_cpus_aml(Aml *table, MachineState *machine, CPUHotplugFeatures opts,
             * as a result _PXM is required for all CPUs which might
             * be hot-plugged. For simplicity, add it for all CPUs.
             */
            j = numa_get_node_for_cpu(i);
            if (j < nb_numa_nodes) {
                aml_append(dev, aml_name_decl("_PXM", aml_int(j)));
            if (arch_ids->cpus[i].props.has_node_id) {
                aml_append(dev, aml_name_decl("_PXM",
                           aml_int(arch_ids->cpus[i].props.node_id)));
            }

            aml_append(cpus_dev, dev);
+7 −12
Original line number Diff line number Diff line
@@ -486,30 +486,25 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
    AcpiSystemResourceAffinityTable *srat;
    AcpiSratProcessorGiccAffinity *core;
    AcpiSratMemoryAffinity *numamem;
    int i, j, srat_start;
    int i, srat_start;
    uint64_t mem_base;
    uint32_t *cpu_node = g_malloc0(vms->smp_cpus * sizeof(uint32_t));

    for (i = 0; i < vms->smp_cpus; i++) {
        j = numa_get_node_for_cpu(i);
        if (j < nb_numa_nodes) {
                cpu_node[i] = j;
        }
    }
    MachineClass *mc = MACHINE_GET_CLASS(vms);
    const CPUArchIdList *cpu_list = mc->possible_cpu_arch_ids(MACHINE(vms));

    srat_start = table_data->len;
    srat = acpi_data_push(table_data, sizeof(*srat));
    srat->reserved1 = cpu_to_le32(1);

    for (i = 0; i < vms->smp_cpus; ++i) {
    for (i = 0; i < cpu_list->len; ++i) {
        int node_id = cpu_list->cpus[i].props.has_node_id ?
            cpu_list->cpus[i].props.node_id : 0;
        core = acpi_data_push(table_data, sizeof(*core));
        core->type = ACPI_SRAT_PROCESSOR_GICC;
        core->length = sizeof(*core);
        core->proximity = cpu_to_le32(cpu_node[i]);
        core->proximity = cpu_to_le32(node_id);
        core->acpi_processor_uid = cpu_to_le32(i);
        core->flags = cpu_to_le32(1);
    }
    g_free(cpu_node);

    mem_base = vms->memmap[VIRT_MEM].base;
    for (i = 0; i < nb_numa_nodes; ++i) {
+101 −22
Original line number Diff line number Diff line
@@ -338,7 +338,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
{
    int cpu;
    int addr_cells = 1;
    unsigned int i;
    const MachineState *ms = MACHINE(vms);

    /*
     * From Documentation/devicetree/bindings/arm/cpus.txt
@@ -369,6 +369,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
    for (cpu = vms->smp_cpus - 1; cpu >= 0; cpu--) {
        char *nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
        ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(cpu));
        CPUState *cs = CPU(armcpu);

        qemu_fdt_add_subnode(vms->fdt, nodename);
        qemu_fdt_setprop_string(vms->fdt, nodename, "device_type", "cpu");
@@ -389,9 +390,9 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
                                  armcpu->mp_affinity);
        }

        i = numa_get_node_for_cpu(cpu);
        if (i < nb_numa_nodes) {
            qemu_fdt_setprop_cell(vms->fdt, nodename, "numa-node-id", i);
        if (ms->possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
            qemu_fdt_setprop_cell(vms->fdt, nodename, "numa-node-id",
                ms->possible_cpus->cpus[cs->cpu_index].props.node_id);
        }

        g_free(nodename);
@@ -1194,10 +1195,35 @@ void virt_machine_done(Notifier *notifier, void *data)
    virt_build_smbios(vms);
}

static uint64_t virt_cpu_mp_affinity(VirtMachineState *vms, int idx)
{
    uint8_t clustersz = ARM_DEFAULT_CPUS_PER_CLUSTER;
    VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);

    if (!vmc->disallow_affinity_adjustment) {
        /* Adjust MPIDR like 64-bit KVM hosts, which incorporate the
         * GIC's target-list limitations. 32-bit KVM hosts currently
         * always create clusters of 4 CPUs, but that is expected to
         * change when they gain support for gicv3. When KVM is enabled
         * it will override the changes we make here, therefore our
         * purposes are to make TCG consistent (with 64-bit KVM hosts)
         * and to improve SGI efficiency.
         */
        if (vms->gic_version == 3) {
            clustersz = GICV3_TARGETLIST_BITS;
        } else {
            clustersz = GIC_TARGETLIST_BITS;
        }
    }
    return arm_cpu_mp_affinity(idx, clustersz);
}

static void machvirt_init(MachineState *machine)
{
    VirtMachineState *vms = VIRT_MACHINE(machine);
    VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(machine);
    MachineClass *mc = MACHINE_GET_CLASS(machine);
    const CPUArchIdList *possible_cpus;
    qemu_irq pic[NUM_IRQS];
    MemoryRegion *sysmem = get_system_memory();
    MemoryRegion *secure_sysmem = NULL;
@@ -1210,7 +1236,6 @@ static void machvirt_init(MachineState *machine)
    CPUClass *cc;
    Error *err = NULL;
    bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
    uint8_t clustersz;

    if (!cpu_model) {
        cpu_model = "cortex-a15";
@@ -1263,10 +1288,8 @@ static void machvirt_init(MachineState *machine)
     */
    if (vms->gic_version == 3) {
        virt_max_cpus = vms->memmap[VIRT_GIC_REDIST].size / 0x20000;
        clustersz = GICV3_TARGETLIST_BITS;
    } else {
        virt_max_cpus = GIC_NCPU;
        clustersz = GIC_TARGETLIST_BITS;
    }

    if (max_cpus > virt_max_cpus) {
@@ -1324,21 +1347,35 @@ static void machvirt_init(MachineState *machine)
        exit(1);
    }

    for (n = 0; n < smp_cpus; n++) {
        Object *cpuobj = object_new(typename);
        if (!vmc->disallow_affinity_adjustment) {
            /* Adjust MPIDR like 64-bit KVM hosts, which incorporate the
             * GIC's target-list limitations. 32-bit KVM hosts currently
             * always create clusters of 4 CPUs, but that is expected to
             * change when they gain support for gicv3. When KVM is enabled
             * it will override the changes we make here, therefore our
             * purposes are to make TCG consistent (with 64-bit KVM hosts)
             * and to improve SGI efficiency.
             */
            uint8_t aff1 = n / clustersz;
            uint8_t aff0 = n % clustersz;
            object_property_set_int(cpuobj, (aff1 << ARM_AFF1_SHIFT) | aff0,
    possible_cpus = mc->possible_cpu_arch_ids(machine);
    for (n = 0; n < possible_cpus->len; n++) {
        Object *cpuobj;
        CPUState *cs;
        int node_id;

        if (n >= smp_cpus) {
            break;
        }

        cpuobj = object_new(typename);
        object_property_set_int(cpuobj, possible_cpus->cpus[n].arch_id,
                                "mp-affinity", NULL);

        cs = CPU(cpuobj);
        cs->cpu_index = n;

        node_id = possible_cpus->cpus[cs->cpu_index].props.node_id;
        if (!possible_cpus->cpus[cs->cpu_index].props.has_node_id) {
            /* by default CPUState::numa_node was 0 if it's not set via CLI
             * keep it this way for now but in future we probably should
             * refuse to start up with incomplete numa mapping */
             node_id = 0;
        }
        if (cs->numa_node == CPU_UNSET_NUMA_NODE_ID) {
            cs->numa_node = node_id;
        } else {
            /* CPU isn't device_add compatible yet, this shouldn't happen */
            error_setg(&error_abort, "user set node-id not implemented");
        }

        if (!vms->secure) {
@@ -1518,6 +1555,46 @@ static void virt_set_gic_version(Object *obj, const char *value, Error **errp)
    }
}

static CpuInstanceProperties
virt_cpu_index_to_props(MachineState *ms, unsigned cpu_index)
{
    MachineClass *mc = MACHINE_GET_CLASS(ms);
    const CPUArchIdList *possible_cpus = mc->possible_cpu_arch_ids(ms);

    assert(cpu_index < possible_cpus->len);
    return possible_cpus->cpus[cpu_index].props;
}

static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
{
    int n;
    VirtMachineState *vms = VIRT_MACHINE(ms);

    if (ms->possible_cpus) {
        assert(ms->possible_cpus->len == max_cpus);
        return ms->possible_cpus;
    }

    ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) +
                                  sizeof(CPUArchId) * max_cpus);
    ms->possible_cpus->len = max_cpus;
    for (n = 0; n < ms->possible_cpus->len; n++) {
        ms->possible_cpus->cpus[n].arch_id =
            virt_cpu_mp_affinity(vms, n);
        ms->possible_cpus->cpus[n].props.has_thread_id = true;
        ms->possible_cpus->cpus[n].props.thread_id = n;

        /* default distribution of CPUs over NUMA nodes */
        if (nb_numa_nodes) {
            /* preset values but do not enable them i.e. 'has_node_id = false',
             * numa init code will enable them later if manual mapping wasn't
             * present on CLI */
            ms->possible_cpus->cpus[n].props.node_id = n % nb_numa_nodes;
        }
    }
    return ms->possible_cpus;
}

static void virt_machine_class_init(ObjectClass *oc, void *data)
{
    MachineClass *mc = MACHINE_CLASS(oc);
@@ -1534,6 +1611,8 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
    mc->pci_allow_0_address = true;
    /* We know we will never create a pre-ARMv7 CPU which needs 1K pages */
    mc->minimum_page_bits = 12;
    mc->possible_cpu_arch_ids = virt_possible_cpu_arch_ids;
    mc->cpu_index_to_instance_props = virt_cpu_index_to_props;
}

static const TypeInfo virt_machine_info = {
Loading