From 5a0ed254f99ca37498bd81994b906b6984b5ffa9 Mon Sep 17 00:00:00 2001 From: Ying Fang Date: Wed, 22 Apr 2020 19:25:00 +0800 Subject: [PATCH] hw/arm64: add vcpu cache info support Support VCPU Cache info by dtb and PPTT table, including L1, L2 and L3 Cache. Signed-off-by: zhanghailiang Signed-off-by: Honghao --- hw/acpi/aml-build.c | 126 ++++++++++++++++++++++++++++++++++++ hw/arm/virt.c | 80 ++++++++++++++++++++++- include/hw/acpi/aml-build.h | 46 +++++++++++++ 3 files changed, 251 insertions(+), 1 deletion(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index f2c8c28f..74e95005 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -55,6 +55,131 @@ static void build_append_array(GArray *array, GArray *val) /* * ACPI 6.2 Processor Properties Topology Table (PPTT) */ +#ifdef __aarch64__ +static void build_cache_head(GArray *tbl, uint32_t next_level) +{ + build_append_byte(tbl, 1); + build_append_byte(tbl, 24); + build_append_int_noprefix(tbl, 0, 2); + build_append_int_noprefix(tbl, 127, 4); + build_append_int_noprefix(tbl, next_level, 4); +} + +static void build_cache_tail(GArray *tbl, uint32_t cache_type) +{ + switch (cache_type) { + case ARM_L1D_CACHE: /* L1 dcache info*/ + build_append_int_noprefix(tbl, ARM_L1DCACHE_SIZE, 4); + build_append_int_noprefix(tbl, ARM_L1DCACHE_SET, 4); + build_append_byte(tbl, ARM_L1DCACHE_ASSOCIATIVITY); + build_append_byte(tbl, ARM_L1DCACHE_ATTRIBUTES); + build_append_int_noprefix(tbl, ARM_L1DCACHE_LINE_SIZE, 2); + break; + case ARM_L1I_CACHE: /* L1 icache info*/ + build_append_int_noprefix(tbl, ARM_L1ICACHE_SIZE, 4); + build_append_int_noprefix(tbl, ARM_L1ICACHE_SET, 4); + build_append_byte(tbl, ARM_L1ICACHE_ASSOCIATIVITY); + build_append_byte(tbl, ARM_L1ICACHE_ATTRIBUTES); + build_append_int_noprefix(tbl, ARM_L1ICACHE_LINE_SIZE, 2); + break; + case ARM_L2_CACHE: /* L2 cache info*/ + build_append_int_noprefix(tbl, ARM_L2CACHE_SIZE, 4); + build_append_int_noprefix(tbl, ARM_L2CACHE_SET, 4); + build_append_byte(tbl, ARM_L2CACHE_ASSOCIATIVITY); + build_append_byte(tbl, ARM_L2CACHE_ATTRIBUTES); + build_append_int_noprefix(tbl, ARM_L2CACHE_LINE_SIZE, 2); + break; + case ARM_L3_CACHE: /* L3 cache info*/ + build_append_int_noprefix(tbl, ARM_L3CACHE_SIZE, 4); + build_append_int_noprefix(tbl, ARM_L3CACHE_SET, 4); + build_append_byte(tbl, ARM_L3CACHE_ASSOCIATIVITY); + build_append_byte(tbl, ARM_L3CACHE_ATTRIBUTES); + build_append_int_noprefix(tbl, ARM_L3CACHE_LINE_SIZE, 2); + break; + default: + build_append_int_noprefix(tbl, 0, 4); + build_append_int_noprefix(tbl, 0, 4); + build_append_byte(tbl, 0); + build_append_byte(tbl, 0); + build_append_int_noprefix(tbl, 0, 2); + break; + } +} + +static void build_cache_hierarchy(GArray *tbl, + uint32_t next_level, uint32_t cache_type) +{ + build_cache_head(tbl, next_level); + build_cache_tail(tbl, cache_type); +} + +static void build_arm_socket_hierarchy(GArray *tbl, + uint32_t offset, uint32_t id) +{ + build_append_byte(tbl, 0); /* Type 0 - processor */ + build_append_byte(tbl, 24); /* Length, add private resources */ + build_append_int_noprefix(tbl, 0, 2); /* Reserved */ + build_append_int_noprefix(tbl, 1, 4); /* Processor boundary and id invalid*/ + build_append_int_noprefix(tbl, 0, 4); + build_append_int_noprefix(tbl, id, 4); + build_append_int_noprefix(tbl, 1, 4); /* Num private resources */ + build_append_int_noprefix(tbl, offset, 4); +} + +static void build_arm_cpu_hierarchy(GArray *tbl, + struct offset_status *offset, uint32_t id) +{ + if (!offset) { + return; + } + build_append_byte(tbl, 0); /* Type 0 - processor */ + build_append_byte(tbl, 32); /* Length, add private resources */ + build_append_int_noprefix(tbl, 0, 2); /* Reserved */ + build_append_int_noprefix(tbl, 2, 4); /* Valid id*/ + build_append_int_noprefix(tbl, offset->parent, 4); + build_append_int_noprefix(tbl, id, 4); + build_append_int_noprefix(tbl, 3, 4); /* Num private resources */ + build_append_int_noprefix(tbl, offset->l1d_offset, 4); + build_append_int_noprefix(tbl, offset->l1i_offset, 4); + build_append_int_noprefix(tbl, offset->l2_offset, 4); +} + +void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) +{ + int pptt_start = table_data->len; + int uid = 0, cpus = 0, socket; + struct offset_status offset; + const MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cores = ms->smp.cores; + + acpi_data_push(table_data, sizeof(AcpiTableHeader)); + + for (socket = 0; cpus < possible_cpus; socket++) { + int core; + uint32_t l3_offset = table_data->len - pptt_start; + build_cache_hierarchy(table_data, 0, ARM_L3_CACHE); + + offset.parent = table_data->len - pptt_start; + build_arm_socket_hierarchy(table_data, l3_offset, socket); + + for (core = 0; core < smp_cores; core++) { + offset.l2_offset = table_data->len - pptt_start; + build_cache_hierarchy(table_data, 0, ARM_L2_CACHE); + offset.l1d_offset = table_data->len - pptt_start; + build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1D_CACHE); + offset.l1i_offset = table_data->len - pptt_start; + build_cache_hierarchy(table_data, offset.l2_offset, ARM_L1I_CACHE); + build_arm_cpu_hierarchy(table_data, &offset, uid++); + cpus++; + } + } + + build_header(linker, table_data, + (void *)(table_data->data + pptt_start), "PPTT", + table_data->len - pptt_start, 1, NULL, NULL); +} + +#else static void build_cpu_hierarchy(GArray *tbl, uint32_t flags, uint32_t parent, uint32_t id) { @@ -103,6 +228,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linker, int possible_cpus) (void *)(table_data->data + pptt_start), "PPTT", table_data->len - pptt_start, 1, NULL, NULL); } +#endif #define ACPI_NAMESEG_LEN 4 diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 272455bc..9669c70b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -308,6 +308,81 @@ static void fdt_add_timer_nodes(const VirtMachineState *vms) GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL2_IRQ, irqflags); } +static void fdt_add_l3cache_nodes(const VirtMachineState *vms) +{ + int i; + const MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cores = ms->smp.cores; + unsigned int sockets = vms->smp_cpus / smp_cores; + + /* If current is not equal to max */ + if (vms->smp_cpus % smp_cores) + sockets++; + + for (i = 0; i < sockets; i++) { + char *nodename = g_strdup_printf("/cpus/l3-cache%d", i); + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cache"); + qemu_fdt_setprop_string(vms->fdt, nodename, "cache-unified", "true"); + qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-level", 3); + qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-size", 0x2000000); + qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-line-size", 128); + qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-sets", 2048); + qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", + qemu_fdt_alloc_phandle(vms->fdt)); + g_free(nodename); + } +} + + +static void fdt_add_l2cache_nodes(const VirtMachineState *vms) +{ + int i, j; + const MachineState *ms = MACHINE(qdev_get_machine()); + unsigned int smp_cores = ms->smp.cores; + signed int sockets = vms->smp_cpus / smp_cores; + + /* If current is not equal to max */ + if (vms->smp_cpus % smp_cores) + sockets++; + + for (i = 0; i < sockets; i++) { + char *next_path = g_strdup_printf("/cpus/l3-cache%d", i); + for (j = 0; j < smp_cores; j++) { + char *nodename = g_strdup_printf("/cpus/l2-cache%d", + i * smp_cores + j); + qemu_fdt_add_subnode(vms->fdt, nodename); + qemu_fdt_setprop_string(vms->fdt, nodename, "compatible", "cache"); + qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-size", 0x80000); + qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-line-size", 64); + qemu_fdt_setprop_cell(vms->fdt, nodename, "cache-sets", 1024); + qemu_fdt_setprop_phandle(vms->fdt, nodename, + "next-level-cache", next_path); + qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", + qemu_fdt_alloc_phandle(vms->fdt)); + g_free(nodename); + } + g_free(next_path); + } +} + +static void fdt_add_l1cache_prop(const VirtMachineState *vms, + char *nodename, int cpu) +{ + char *cachename = g_strdup_printf("/cpus/l2-cache%d", cpu); + + qemu_fdt_setprop_cell(vms->fdt, nodename, "d-cache-size", 0x10000); + qemu_fdt_setprop_cell(vms->fdt, nodename, "d-cache-line-size", 64); + qemu_fdt_setprop_cell(vms->fdt, nodename, "d-cache-sets", 256); + qemu_fdt_setprop_cell(vms->fdt, nodename, "i-cache-size", 0x10000); + qemu_fdt_setprop_cell(vms->fdt, nodename, "i-cache-line-size", 64); + qemu_fdt_setprop_cell(vms->fdt, nodename, "i-cache-sets", 256); + qemu_fdt_setprop_phandle(vms->fdt, nodename, + "next-level-cache", cachename); + g_free(cachename); +} + + static void fdt_add_cpu_nodes(const VirtMachineState *vms) { int cpu; @@ -341,6 +416,9 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#address-cells", addr_cells); qemu_fdt_setprop_cell(vms->fdt, "/cpus", "#size-cells", 0x0); + fdt_add_l3cache_nodes(vms); + fdt_add_l2cache_nodes(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)); @@ -369,7 +447,7 @@ static void fdt_add_cpu_nodes(const VirtMachineState *vms) qemu_fdt_setprop_cell(vms->fdt, nodename, "numa-node-id", ms->possible_cpus->cpus[cs->cpu_index].props.node_id); } - + fdt_add_l1cache_prop(vms, nodename, cpu); qemu_fdt_setprop_cell(vms->fdt, nodename, "phandle", qemu_fdt_alloc_phandle(vms->fdt)); diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index bfb0b100..0be3453a 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -223,6 +223,52 @@ struct AcpiBuildTables { BIOSLinker *linker; } AcpiBuildTables; +#ifdef __aarch64__ +/* Definitions of the hardcoded cache info*/ + +typedef enum { + ARM_L1D_CACHE, + ARM_L1I_CACHE, + ARM_L2_CACHE, + ARM_L3_CACHE +} ArmCacheType; + +/* L1 data cache: */ +#define ARM_L1DCACHE_SIZE 65536 +#define ARM_L1DCACHE_SET 256 +#define ARM_L1DCACHE_ASSOCIATIVITY 4 +#define ARM_L1DCACHE_ATTRIBUTES 2 +#define ARM_L1DCACHE_LINE_SIZE 64 + +/* L1 instruction cache: */ +#define ARM_L1ICACHE_SIZE 65536 +#define ARM_L1ICACHE_SET 256 +#define ARM_L1ICACHE_ASSOCIATIVITY 4 +#define ARM_L1ICACHE_ATTRIBUTES 4 +#define ARM_L1ICACHE_LINE_SIZE 64 + +/* Level 2 unified cache: */ +#define ARM_L2CACHE_SIZE 524288 +#define ARM_L2CACHE_SET 1024 +#define ARM_L2CACHE_ASSOCIATIVITY 8 +#define ARM_L2CACHE_ATTRIBUTES 10 +#define ARM_L2CACHE_LINE_SIZE 64 + +/* Level 3 unified cache: */ +#define ARM_L3CACHE_SIZE 33554432 +#define ARM_L3CACHE_SET 2048 +#define ARM_L3CACHE_ASSOCIATIVITY 15 +#define ARM_L3CACHE_ATTRIBUTES 10 +#define ARM_L3CACHE_LINE_SIZE 128 + +struct offset_status { + uint32_t parent; + uint32_t l2_offset; + uint32_t l1d_offset; + uint32_t l1i_offset; +}; + +#endif /** * init_aml_allocator: * -- 2.23.0