From 73fc4af05ebe12d77915e6b3c85c48f5e0c432f3 Mon Sep 17 00:00:00 2001
From: Ying Fang <fangying1@huawei.com>
Date: Wed, 22 Apr 2020 19:23:27 +0800
Subject: [PATCH] hw/arm/virt: Introduce cpu topology support

Add topology support for guest vcpu by cpu-map in dtb when the guest is booted
with dtb, and by pptt table when the guest is booted with acpi.

Signed-off-by: Honghao <honghao5@huawei.com>
Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com>
(picked-from https://patchwork.ozlabs.org/cover/939301/ which is pushed by
Andrew Jones <drjones@redhat.com>)
---
 device_tree.c                | 32 ++++++++++++++++++++++
 hw/acpi/aml-build.c          | 53 ++++++++++++++++++++++++++++++++++++
 hw/arm/virt-acpi-build.c     |  4 +++
 hw/arm/virt.c                | 32 +++++++++++++++++++++-
 include/hw/acpi/aml-build.h  |  2 ++
 include/sysemu/device_tree.h |  1 +
 6 files changed, 123 insertions(+), 1 deletion(-)

diff --git a/device_tree.c b/device_tree.c
index f8b46b3c..03906a14 100644
--- a/device_tree.c
+++ b/device_tree.c
@@ -524,6 +524,38 @@ int qemu_fdt_add_subnode(void *fdt, const char *name)
     return retval;
 }

+/**
+ * qemu_fdt_add_path
+ * @fdt: Flattened Device Tree
+ * @path: Flattened Device Tree node path
+ *
+ * qemu_fdt_add_path works like qemu_fdt_add_subnode, except it
+ * also recursively adds any missing parent nodes.
+ */
+int qemu_fdt_add_path(void *fdt, const char *path)
+{
+    char *parent;
+    int offset;
+
+    offset = fdt_path_offset(fdt, path);
+    if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
+        error_report("%s Couldn't find node %s: %s", __func__, path,
+                      fdt_strerror(offset));
+        exit(1);
+    }
+
+    if (offset != -FDT_ERR_NOTFOUND) {
+        return offset;
+    }
+
+    parent = g_strdup(path);
+    strrchr(parent, '/')[0] = '\0';
+    qemu_fdt_add_path(fdt, parent);
+    g_free(parent);
+
+    return qemu_fdt_add_subnode(fdt, path);
+}
+
 void qemu_fdt_dumpdtb(void *fdt, int size)
 {
     const char *dumpdtb = qemu_opt_get(qemu_get_machine_opts(), "dumpdtb");
diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c
index 73f97751..f2c8c28f 100644
--- a/hw/acpi/aml-build.c
+++ b/hw/acpi/aml-build.c
@@ -25,6 +25,7 @@
 #include "qemu/bswap.h"
 #include "qemu/bitops.h"
 #include "sysemu/numa.h"
+#include "sysemu/cpus.h"

 static GArray *build_alloc_array(void)
 {
@@ -51,6 +52,58 @@ static void build_append_array(GArray *array, GArray *val)
     g_array_append_vals(array, val->data, val->len);
 }

+/*
+ * ACPI 6.2 Processor Properties Topology Table (PPTT)
+ */
+static void build_cpu_hierarchy(GArray *tbl, uint32_t flags,
+                                uint32_t parent, uint32_t id)
+{
+    build_append_byte(tbl, 0);            /* Type 0 - processor */
+    build_append_byte(tbl, 20);           /* Length, no private resources */
+    build_append_int_noprefix(tbl, 0, 2); /* Reserved */
+    build_append_int_noprefix(tbl, flags, 4);
+    build_append_int_noprefix(tbl, parent, 4);
+    build_append_int_noprefix(tbl, id, 4);
+    build_append_int_noprefix(tbl, 0, 4); /* Num private resources */
+}
+
+void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus)
+{
+    int pptt_start = table_data->len;
+    int uid = 0, cpus = 0, socket;
+    MachineState *ms = MACHINE(qdev_get_machine());
+    unsigned int smp_cores = ms->smp.cores;
+    unsigned int smp_threads = ms->smp.threads;
+
+    acpi_data_push(table_data, sizeof(AcpiTableHeader));
+
+    for (socket = 0; cpus < possible_cpus; socket++) {
+        uint32_t socket_offset = table_data->len - pptt_start;
+        int core;
+
+        build_cpu_hierarchy(table_data, 1, 0, socket);
+
+        for (core = 0; core < smp_cores; core++) {
+            uint32_t core_offset = table_data->len - pptt_start;
+            int thread;
+
+            if (smp_threads > 1) {
+                build_cpu_hierarchy(table_data, 0, socket_offset, core);
+                for (thread = 0; thread < smp_threads; thread++) {
+                    build_cpu_hierarchy(table_data, 2, core_offset, uid++);
+                }
+             } else {
+                build_cpu_hierarchy(table_data, 2, socket_offset, uid++);
+             }
+        }
+        cpus += smp_cores * smp_threads;
+    }
+
+    build_header(linker, table_data,
+                 (void *)(table_data->data + pptt_start), "PPTT",
+                 table_data->len - pptt_start, 1, NULL, NULL);
+}
+
 #define ACPI_NAMESEG_LEN 4

 static void
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 29494ebd..fe54411f 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -848,6 +848,10 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables)
     acpi_add_table(table_offsets, tables_blob);
     build_fadt_rev5(tables_blob, tables->linker, vms, dsdt);

+    acpi_add_table(table_offsets, tables_blob);
+
+    build_pptt(tables_blob, tables->linker, vms->smp_cpus);
+
     acpi_add_table(table_offsets, tables_blob);
     build_madt(tables_blob, tables->linker, vms);

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 0fa355ba..272455bc 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -44,6 +44,7 @@
 #include "net/net.h"
 #include "sysemu/device_tree.h"
 #include "sysemu/numa.h"
+#include "sysemu/cpus.h"
 #include "sysemu/sysemu.h"
 #include "sysemu/kvm.h"
 #include "hw/loader.h"
@@ -312,7 +313,8 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
     int cpu;
     int addr_cells = 1;
     const MachineState *ms = MACHINE(vms);
-
+    unsigned int smp_cores = ms->smp.cores;
+    unsigned int smp_threads = ms->smp.threads;
     /*
      * From Documentation/devicetree/bindings/arm/cpus.txt
      *  On ARM v8 64-bit systems value should be set to 2,
@@ -368,8 +370,36 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms)
                 ms->possible_cpus->cpus[cs->cpu_index].props.node_id);
         }

+        qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle",
+                              qemu_fdt_alloc_phandle(vms->fdt));
+
         g_free(nodename);
     }
+
+    /* Add vcpu topology by fdt node cpu-map. */
+    qemu_fdt_add_subnode(vms->fdt, "/cpus/cpu-map");
+
+    for (cpu = vms->smp_cpus - 1; cpu >= 0; cpu--) {
+        char *cpu_path = g_strdup_printf("/cpus/cpu@%d", cpu);
+        char *map_path;
+
+        if (smp_threads > 1) {
+            map_path = g_strdup_printf(
+                           "/cpus/cpu-map/%s%d/%s%d/%s%d",
+                           "cluster", cpu / (smp_cores * smp_threads),
+                           "core", (cpu / smp_threads) % smp_cores,
+                           "thread", cpu % smp_threads);
+        } else {
+            map_path = g_strdup_printf(
+                           "/cpus/cpu-map/%s%d/%s%d",
+                           "cluster", cpu / smp_cores,
+                           "core", cpu % smp_cores);
+        }
+        qemu_fdt_add_path(vms->fdt, map_path);
+        qemu_fdt_setprop_phandle(vms->fdt, map_path, "cpu", cpu_path);
+        g_free(map_path);
+        g_free(cpu_path);
+    }
 }

 static void fdt_add_its_gic_node(VirtMachineState *vms)
diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h
index 375335ab..bfb0b100 100644
--- a/include/hw/acpi/aml-build.h
+++ b/include/hw/acpi/aml-build.h
@@ -417,6 +417,8 @@ build_append_gas_from_struct(GArray *table, const struct AcpiGenericAddress *s)
 void build_srat_memory(AcpiSratMemoryAffinity *numamem, uint64_t base,
                        uint64_t len, int node, MemoryAffinityFlags flags);

+void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus);
+
 void build_slit(GArray *table_data, BIOSLinker *linker);

 void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f,
diff --git a/include/sysemu/device_tree.h b/include/sysemu/device_tree.h
index c16fd69b..d62fc873 100644
--- a/include/sysemu/device_tree.h
+++ b/include/sysemu/device_tree.h
@@ -101,6 +101,7 @@ uint32_t qemu_fdt_get_phandle(void *fdt, const char *path);
 uint32_t qemu_fdt_alloc_phandle(void *fdt);
 int qemu_fdt_nop_node(void *fdt, const char *node_path);
 int qemu_fdt_add_subnode(void *fdt, const char *name);
+int qemu_fdt_add_path(void *fdt, const char *path);

 #define qemu_fdt_setprop_cells(fdt, node_path, property, ...)                 \
     do {                                                                      \
--
2.23.0
