Add topological relationships for Loongarch VCPU and initialize
topology member variables.
On LoongArch system there is socket/core/thread topo information,
physical CPU id is calculated from CPU topo, every topo sub-field is
aligned by power of 2. So it is different from logical cpu index.
Co-developed-by: Xianglai Li <lixianglai@loongson.cn>
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
hw/loongarch/virt.c | 59 ++++++++++++++++++++++++++++++++++++------
target/loongarch/cpu.h | 6 +++++
2 files changed, 57 insertions(+), 8 deletions(-)
diff --git a/hw/loongarch/virt.c b/hw/loongarch/virt.c
index 907f965c54..2bbbbbfbcf 100644
--- a/hw/loongarch/virt.c
+++ b/hw/loongarch/virt.c
@@ -774,6 +774,48 @@ static void virt_initfn(Object *obj)
virt_flash_create(lvms);
}
+static void virt_get_topo_from_index(MachineState *ms,
+ LoongArchCPUTopo *topo, int index)
+{
+ topo->socket_id = index / (ms->smp.cores * ms->smp.threads);
+ topo->core_id = index / ms->smp.threads % ms->smp.cores;
+ topo->thread_id = index % ms->smp.threads;
+}
+
+static unsigned int topo_align_up(unsigned int count)
+{
+ g_assert(count >= 1);
+ count -= 1;
+ return BIT(count ? 32 - clz32(count) : 0);
+}
+
+/*
+ * LoongArch Reference Manual Vol1, Chapter 7.4.12 CPU Identity
+ * For CPU architecture, bit0 .. bit8 is valid for CPU id, max cpuid is 512
+ * However for IPI/Eiointc interrupt controller, max supported cpu id for
+ * irq routingis 256
+ *
+ * Here max cpu id is 256 for virt machine
+ */
+static int virt_get_arch_id_from_topo(MachineState *ms, LoongArchCPUTopo *topo)
+{
+ int arch_id, threads, cores, sockets;
+
+ threads = topo_align_up(ms->smp.threads);
+ cores = topo_align_up(ms->smp.cores);
+ sockets = topo_align_up(ms->smp.sockets);
+ if ((threads * cores * sockets) > 256) {
+ error_report("Exceeding max cpuid 256 with sockets[%d] cores[%d]"
+ " threads[%d]", ms->smp.sockets, ms->smp.cores,
+ ms->smp.threads);
+ exit(1);
+ }
+
+ arch_id = topo->thread_id + topo->core_id * threads;
+ arch_id += topo->socket_id * threads * cores;
+ return arch_id;
+}
+
static bool memhp_type_supported(DeviceState *dev)
{
/* we only support pc dimm now */
@@ -873,8 +915,9 @@ static HotplugHandler *virt_get_hotplug_handler(MachineState *machine,
static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
{
- int n;
+ int n, arch_id;
unsigned int max_cpus = ms->smp.max_cpus;
+ LoongArchCPUTopo topo;
if (ms->possible_cpus) {
assert(ms->possible_cpus->len == max_cpus);
@@ -885,17 +928,17 @@ static const CPUArchIdList *virt_possible_cpu_arch_ids(MachineState *ms)
sizeof(CPUArchId) * max_cpus);
ms->possible_cpus->len = max_cpus;
for (n = 0; n < ms->possible_cpus->len; n++) {
+ virt_get_topo_from_index(ms, &topo, n);
+ arch_id = virt_get_arch_id_from_topo(ms, &topo);
ms->possible_cpus->cpus[n].type = ms->cpu_type;
- ms->possible_cpus->cpus[n].arch_id = n;
-
+ ms->possible_cpus->cpus[n].arch_id = arch_id;
+ ms->possible_cpus->cpus[n].vcpus_count = 1;
ms->possible_cpus->cpus[n].props.has_socket_id = true;
- ms->possible_cpus->cpus[n].props.socket_id =
- n / (ms->smp.cores * ms->smp.threads);
+ ms->possible_cpus->cpus[n].props.socket_id = topo.socket_id;
ms->possible_cpus->cpus[n].props.has_core_id = true;
- ms->possible_cpus->cpus[n].props.core_id =
- n / ms->smp.threads % ms->smp.cores;
+ 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->smp.threads;
+ ms->possible_cpus->cpus[n].props.thread_id = topo.thread_id;
}
return ms->possible_cpus;
}
diff --git a/target/loongarch/cpu.h b/target/loongarch/cpu.h
index 83183a33ab..9dc71fa7f1 100644
--- a/target/loongarch/cpu.h
+++ b/target/loongarch/cpu.h
@@ -393,6 +393,12 @@ typedef struct CPUArchState {
#endif
} CPULoongArchState;
+typedef struct LoongArchCPUTopo {
+ int32_t socket_id; /* socket-id of this VCPU */
+ int32_t core_id; /* core-id of this VCPU */
+ int32_t thread_id; /* thread-id of this VCPU */
+} LoongArchCPUTopo;
+
/**
* LoongArchCPU:
* @env: #CPULoongArchState
--
2.43.5