diff --git a/arm-virt-Add-CPU-topology-support.patch b/arm-virt-Add-CPU-topology-support.patch new file mode 100644 index 0000000..016b3ed --- /dev/null +++ b/arm-virt-Add-CPU-topology-support.patch @@ -0,0 +1,269 @@ +From 5454c00908236dcabcbf9ae246ccb69e1fcea72e Mon Sep 17 00:00:00 2001 +From: Keqian Zhu +Date: Mon, 6 Apr 2020 10:54:35 +0800 +Subject: [PATCH] arm/virt: Add CPU topology support + +The CPU topology specified by user (through -smp options) is used in +ACPI PPTT. Now we will use this information to locate which CPU to +plug or unplug. + +Signed-off-by: Keqian Zhu +Signed-off-by: Salil Mehta +--- + hw/arm/virt.c | 87 ++++++++++++++++++++++++++++++++++++++- + include/hw/arm/topology.h | 68 ++++++++++++++++++++++++++++++ + qapi/machine.json | 2 + + target/arm/cpu.c | 4 ++ + target/arm/cpu.h | 4 ++ + 5 files changed, 163 insertions(+), 2 deletions(-) + create mode 100644 include/hw/arm/topology.h + +diff --git a/hw/arm/virt.c b/hw/arm/virt.c +index 11155fcb70..a12e718686 100644 +--- a/hw/arm/virt.c ++++ b/hw/arm/virt.c +@@ -39,6 +39,7 @@ + #include "hw/sysbus.h" + #include "hw/arm/boot.h" + #include "hw/arm/primecell.h" ++#include "hw/arm/topology.h" + #include "hw/arm/virt.h" + #include "hw/block/flash.h" + #include "hw/vfio/vfio-calxeda-xgmac.h" +@@ -2524,6 +2525,7 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + int n; + unsigned int max_cpus = ms->smp.max_cpus; + VirtMachineState *vms = VIRT_MACHINE(ms); ++ ARMCPUTopoInfo topo; + + if (ms->possible_cpus) { + assert(ms->possible_cpus->len == max_cpus); +@@ -2535,10 +2537,19 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms) + ms->possible_cpus->len = max_cpus; + for (n = 0; n < ms->possible_cpus->len; n++) { + ms->possible_cpus->cpus[n].type = ms->cpu_type; ++ ms->possible_cpus->cpus[n].vcpus_count = 1; + ms->possible_cpus->cpus[n].arch_id = + virt_cpu_mp_affinity(vms, n); ++ ++ topo_ids_from_idx(n, ms->smp.clusters, ms->smp.cores, ms->smp.threads, &topo); ++ ms->possible_cpus->cpus[n].props.has_socket_id = true; ++ ms->possible_cpus->cpus[n].props.socket_id = topo.pkg_id; ++ ms->possible_cpus->cpus[n].props.has_cluster_id = true; ++ ms->possible_cpus->cpus[n].props.cluster_id = topo.cluster_id; ++ ms->possible_cpus->cpus[n].props.has_core_id = true; ++ ms->possible_cpus->cpus[n].props.core_id = topo.core_id; + ms->possible_cpus->cpus[n].props.has_thread_id = true; +- ms->possible_cpus->cpus[n].props.thread_id = n; ++ ms->possible_cpus->cpus[n].props.thread_id = topo.smt_id; + } + return ms->possible_cpus; + } +@@ -2589,7 +2600,79 @@ static void virt_memory_plug(HotplugHandler *hotplug_dev, + static void virt_cpu_pre_plug(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) + { +- /* Currently nothing to do */ ++ CPUState *cs = CPU(dev); ++ ARMCPUTopoInfo topo; ++ ARMCPU *cpu = ARM_CPU(dev); ++ MachineState *ms = MACHINE(hotplug_dev); ++ int smp_clusters = ms->smp.clusters; ++ int smp_cores = ms->smp.cores; ++ int smp_threads = ms->smp.threads; ++ ++ /* if cpu idx is not set, set it based on socket/cluster/core/thread ++ * properties ++ */ ++ if (cs->cpu_index == UNASSIGNED_CPU_INDEX) { ++ int max_socket = ms->smp.max_cpus / smp_threads / smp_cores / smp_clusters; ++ if (cpu->socket_id < 0 || cpu->socket_id >= max_socket) { ++ error_setg(errp, "Invalid CPU socket-id: %u must be in range 0:%u", ++ cpu->socket_id, max_socket - 1); ++ return; ++ } ++ if (cpu->cluster_id < 0 || cpu->cluster_id >= smp_clusters) { ++ error_setg(errp, "Invalid CPU cluster-id: %u must be in range 0:%u", ++ cpu->cluster_id, smp_clusters - 1); ++ return; ++ } ++ if (cpu->core_id < 0 || cpu->core_id >= smp_cores) { ++ 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 || cpu->thread_id >= smp_threads) { ++ error_setg(errp, "Invalid CPU thread-id: %u must be in range 0:%u", ++ cpu->thread_id, smp_threads - 1); ++ return; ++ } ++ ++ topo.pkg_id = cpu->socket_id; ++ topo.cluster_id = cpu->cluster_id; ++ topo.core_id = cpu->core_id; ++ topo.smt_id = cpu->thread_id; ++ cs->cpu_index = idx_from_topo_ids(smp_clusters, smp_cores, smp_threads, &topo); ++ } ++ ++ /* if 'address' properties socket-id/cluster-id/core-id/thread-id are not ++ * set, set them so that machine_query_hotpluggable_cpus would show correct ++ * values ++ */ ++ topo_ids_from_idx(cs->cpu_index, smp_clusters, smp_cores, smp_threads, &topo); ++ if (cpu->socket_id != -1 && cpu->socket_id != topo.pkg_id) { ++ error_setg(errp, "property socket-id: %u doesn't match set idx:" ++ " 0x%x (socket-id: %u)", cpu->socket_id, cs->cpu_index, topo.pkg_id); ++ return; ++ } ++ cpu->socket_id = topo.pkg_id; ++ ++ if (cpu->cluster_id != -1 && cpu->cluster_id != topo.cluster_id) { ++ error_setg(errp, "property cluster-id: %u doesn't match set idx:" ++ " 0x%x (cluster-id: %u)", cpu->cluster_id, cs->cpu_index, topo.cluster_id); ++ return; ++ } ++ cpu->cluster_id = topo.cluster_id; ++ ++ if (cpu->core_id != -1 && cpu->core_id != topo.core_id) { ++ error_setg(errp, "property core-id: %u doesn't match set idx:" ++ " 0x%x (core-id: %u)", cpu->core_id, cs->cpu_index, topo.core_id); ++ return; ++ } ++ cpu->core_id = topo.core_id; ++ ++ if (cpu->thread_id != -1 && cpu->thread_id != topo.smt_id) { ++ error_setg(errp, "property thread-id: %u doesn't match set idx:" ++ " 0x%x (thread-id: %u)", cpu->thread_id, cs->cpu_index, topo.smt_id); ++ return; ++ } ++ cpu->thread_id = topo.smt_id; + } + + static void virt_cpu_plug(HotplugHandler *hotplug_dev, +diff --git a/include/hw/arm/topology.h b/include/hw/arm/topology.h +new file mode 100644 +index 0000000000..d0dad1a9a3 +--- /dev/null ++++ b/include/hw/arm/topology.h +@@ -0,0 +1,68 @@ ++/* ++ * ARM CPU topology data structures and functions ++ * ++ * Copyright (c) 2020 HUAWEI TECHNOLOGIES CO.,LTD. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, see . ++ */ ++ ++#ifndef HW_ARM_TOPOLOGY_H ++#define HW_ARM_TOPOLOGY_H ++ ++typedef struct ARMCPUTopoInfo { ++ unsigned pkg_id; ++ unsigned cluster_id; ++ unsigned core_id; ++ unsigned smt_id; ++} ARMCPUTopoInfo; ++ ++/* Calculate (contiguous) CPU index based on topology */ ++static inline unsigned idx_from_topo_ids(unsigned nr_clusters, ++ unsigned nr_cores, ++ unsigned nr_threads, ++ const ARMCPUTopoInfo *topo) ++{ ++ assert(nr_clusters > 0); ++ assert(nr_cores > 0); ++ assert(nr_threads > 0); ++ assert(topo != NULL); ++ ++ return topo->pkg_id * nr_clusters * nr_cores * nr_threads + ++ topo->cluster_id * nr_cores + ++ topo->core_id * nr_threads + ++ topo->smt_id; ++} ++ ++/* Calculate thread/core/cluster/package topology ++ * based on (contiguous) CPU index ++ */ ++static inline void topo_ids_from_idx(unsigned cpu_index, ++ unsigned nr_clusters, ++ unsigned nr_cores, ++ unsigned nr_threads, ++ ARMCPUTopoInfo *topo) ++{ ++ assert(nr_clusters > 0); ++ assert(nr_cores > 0); ++ assert(nr_threads > 0); ++ assert(topo != NULL); ++ ++ topo->smt_id = cpu_index % nr_threads; ++ topo->core_id = cpu_index / nr_threads % nr_cores; ++ topo->cluster_id = cpu_index / nr_threads / nr_cores % nr_clusters; ++ topo->pkg_id = cpu_index / nr_threads / nr_cores / nr_clusters; ++} ++ ++#endif /* HW_ARM_TOPOLOGY_H */ ++ +diff --git a/qapi/machine.json b/qapi/machine.json +index 8faa51074e..6822cafe2e 100644 +--- a/qapi/machine.json ++++ b/qapi/machine.json +@@ -868,6 +868,7 @@ + # @node-id: NUMA node ID the CPU belongs to + # @socket-id: socket number within node/board the CPU belongs to + # @die-id: die number within socket the CPU belongs to (since 4.1) ++# @cluster-id: cluster number within die the CPU belongs to (since 6.2) + # @core-id: core number within die the CPU belongs to + # @thread-id: thread number within core the CPU belongs to + # +@@ -883,6 +884,7 @@ + 'data': { '*node-id': 'int', + '*socket-id': 'int', + '*die-id': 'int', ++ '*cluster-id': 'int', + '*core-id': 'int', + '*thread-id': 'int' + } +diff --git a/target/arm/cpu.c b/target/arm/cpu.c +index f06ba29885..9fd8e57971 100644 +--- a/target/arm/cpu.c ++++ b/target/arm/cpu.c +@@ -2507,6 +2507,10 @@ static Property arm_cpu_properties[] = { + DEFINE_PROP_UINT64("mp-affinity", ARMCPU, + mp_affinity, ARM64_AFFINITY_INVALID), + DEFINE_PROP_INT32("node-id", ARMCPU, node_id, CPU_UNSET_NUMA_NODE_ID), ++ DEFINE_PROP_INT32("socket-id", ARMCPU, socket_id, -1), ++ DEFINE_PROP_INT32("cluster-id", ARMCPU, cluster_id, -1), ++ DEFINE_PROP_INT32("core-id", ARMCPU, core_id, -1), ++ DEFINE_PROP_INT32("thread-id", ARMCPU, thread_id, -1), + DEFINE_PROP_INT32("core-count", ARMCPU, core_count, -1), + DEFINE_PROP_END_OF_LIST() + }; +diff --git a/target/arm/cpu.h b/target/arm/cpu.h +index 947897d5ac..eb804dffaa 100644 +--- a/target/arm/cpu.h ++++ b/target/arm/cpu.h +@@ -1006,6 +1006,10 @@ struct ARMCPU { + QLIST_HEAD(, ARMELChangeHook) el_change_hooks; + + int32_t node_id; /* NUMA node this CPU belongs to */ ++ int32_t socket_id; ++ int32_t cluster_id; ++ int32_t core_id; ++ int32_t thread_id; + + /* Used to synchronize KVM and QEMU in-kernel device levels */ + uint8_t device_irq_level; +-- +2.27.0 +