79c4324644
Change-Id: I2d302dda68298877c65c99147f5bf22186a59aac
270 lines
10 KiB
Diff
270 lines
10 KiB
Diff
From 5454c00908236dcabcbf9ae246ccb69e1fcea72e Mon Sep 17 00:00:00 2001
|
|
From: Keqian Zhu <zhukeqian1@huawei.com>
|
|
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 <zhukeqian1@huawei.com>
|
|
Signed-off-by: Salil Mehta <salil.mehta@huawei.com>
|
|
---
|
|
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 <http://www.gnu.org/licenses/>.
|
|
+ */
|
|
+
|
|
+#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
|
|
|