From nobody Sun Nov 24 07:02:19 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=nongnu.org ARC-Seal: i=1; a=rsa-sha256; t=1726148474; cv=none; d=zohomail.com; s=zohoarc; b=K4fWWaXtCi53FQP/cjH2k/EYr7vNvbbVaud+0xCdb+RLEvIwXtagCxEGZDTDd5G6o+56dw8zWCVOfT2sTJtXKEKU+DWuFExatjxAm3RIg0GX75jw8FjIevPe5in6hN+squFH/rhBuw+3/DIAjeKFtCEiSBgTJ07xsuj9EDaW6mQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1726148474; h=Content-Type:Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Sender:Subject:Subject:To:To:Message-Id; bh=UQ3jsQjkxvxtaAQyqsb8oEcUK4sRZFy3Mra+veaDWYs=; b=OxEcDxCo8VhYoW5iwqcFUS/Z/yg+3LOndyS2BPiyUHZJcfxameTeRP5pHuAJqtGEwE5zWkc65OU5r6C+BzuY6LDpJHw2WOOHPoPyp7hrnv9JTf1ylRFJz8H6EF4NdnyfFydeSDv1GwOqkeKy2VmO8o5KBRobvGy1uIx25FO0hC0= ARC-Authentication-Results: i=1; mx.zohomail.com; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1726148474302704.789785586091; Thu, 12 Sep 2024 06:41:14 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sok49-0001TC-Ul; Thu, 12 Sep 2024 09:40:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sok48-0001OL-NW; Thu, 12 Sep 2024 09:40:56 -0400 Received: from frasgout.his.huawei.com ([185.176.79.56]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sok45-0000PJ-Uq; Thu, 12 Sep 2024 09:40:56 -0400 Received: from mail.maildlp.com (unknown [172.18.186.231]) by frasgout.his.huawei.com (SkyGuard) with ESMTP id 4X4JNx3B75z6K6Yp; Thu, 12 Sep 2024 21:36:01 +0800 (CST) Received: from frapeml500003.china.huawei.com (unknown [7.182.85.28]) by mail.maildlp.com (Postfix) with ESMTPS id 2FD73140B38; Thu, 12 Sep 2024 21:40:52 +0800 (CST) Received: from a2303103017.china.huawei.com (10.48.147.42) by frapeml500003.china.huawei.com (7.182.85.28) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.1.2507.39; Thu, 12 Sep 2024 15:40:51 +0200 To: , CC: , , , , , , , , , , , , , , , , , Subject: [PATCH 4/5] hw/acpi: add cache hierarchy node to pptt table Date: Thu, 12 Sep 2024 14:38:28 +0100 Message-ID: <20240912133829.400-5-alireza.sanaee@huawei.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240912133829.400-1-alireza.sanaee@huawei.com> References: <20240912133829.400-1-alireza.sanaee@huawei.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Originating-IP: [10.48.147.42] X-ClientProxiedBy: lhrpeml100003.china.huawei.com (7.191.160.210) To frapeml500003.china.huawei.com (7.182.85.28) Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=185.176.79.56; envelope-from=alireza.sanaee@huawei.com; helo=frasgout.his.huawei.com X-Spam_score_int: -41 X-Spam_score: -4.2 X-Spam_bar: ---- X-Spam_report: (-4.2 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Alireza Sanaee From: Alireza Sanaee via Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1726148475521116600 Content-Type: text/plain; charset="utf-8" Specify which layer (core/cluster/socket) caches found at in the CPU topology. Example: Here, 2 sockets (packages), and 2 clusters, 4 cores and 2 threads created, in aggregate 2*2*4*2 logical cores. In the smp-cache object, cores will have l1d and l1i (threads will share these caches by default. However, extending this is not difficult). The clusters will share a unified l2 level cache, and finally sockets will share l3. In this patch, threads will share l1 caches by default, but this can be adjusted if case required. Currently only three levels of caches are supported. Also, PPTT table revision has been increased to 3 even in scenarios where there are no caches. The patch does not allow partial declaration of caches. In another word, all caches must be defined or caches must be skipped. ./qemu-system-aarch64 \ -machine virt,smp-cache.0.cache=3Dl1i,smp-cache.0.topology=3Dcore,smp-cache= .1.cache=3Dl1d,smp-cache.1.topology=3Dcore,smp-cache.2.cache=3Dl2,smp-cache= .2.topology=3Dcluster,smp-cache.3.cache=3Dl3,smp-cache.3.topology=3Dsocket \ -cpu max \ -m 2048 \ -smp sockets=3D2,clusters=3D2,cores=3D4,threads=3D2 \ -kernel ./Image.gz \ -append "console=3DttyAMA0 root=3D/dev/ram rdinit=3D/init acpi=3Dforce" \ -initrd rootfs.cpio.gz \ -bios ./edk2-aarch64-code.fd \ -nographic Signed-off-by: Alireza Sanaee Co-developed-by: Jonathan Cameron Signed-off-by: Jonathan Cameron --- hw/acpi/aml-build.c | 312 +++++++++++++++++++++++++++++++++++- hw/arm/virt-acpi-build.c | 137 +++++++++++++++- hw/arm/virt.c | 5 + hw/loongarch/acpi-build.c | 3 +- include/hw/acpi/aml-build.h | 20 ++- 5 files changed, 468 insertions(+), 9 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index 6d4517cfbe..76acf3e548 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -1964,6 +1964,203 @@ void build_slit(GArray *table_data, BIOSLinker *lin= ker, MachineState *ms, acpi_table_end(linker, &table); } =20 +static bool cache_described_at(MachineState *ms, CpuTopologyLevel level) +{ + if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3) =3D=3D l= evel || + machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2) =3D=3D l= evel || + machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I) =3D=3D = level || + machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D) =3D=3D = level) { + return true; + } + + return false; +} + +static int partial_cache_description(MachineState *ms, ACPIPPTTCache* cach= es, + int num_caches) +{ + int level, c; + + for (level =3D 1; level < num_caches; level++) { + for (c =3D 0; c < num_caches; c++) { + if (caches[c].level !=3D level) { + continue; + } + + switch (level) { + case 1: + /* + * L1 cache is assumed to have both L1I and L1D available. + * Technically both need to be checked. + */ + if (machine_get_cache_topo_level(ms, + CACHE_LEVEL_AND_TYPE_L1I)= =3D=3D + CPU_TOPOLOGY_LEVEL_DEFAULT) + { + assert(machine_get_cache_topo_level(ms, + CACHE_LEVEL_AND_TYPE_L1D) =3D=3D + CPU_TOPOLOGY_LEVEL_DEFAULT); + return level; + } + break; + case 2: + if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_= L2) =3D=3D + CPU_TOPOLOGY_LEVEL_DEFAULT) { + return level; + } + break; + case 3: + if (machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_= L3) =3D=3D + CPU_TOPOLOGY_LEVEL_DEFAULT) { + return level; + } + break; + } + } + } + + return 0; +} + +/* + * This function assumes l3 and l2 have unified cache and l1 is split l1d + * and l1i, and further prepares the lowest cache level for a topology + * level. The info will be fed to build_caches to create caches at the + * right level. + */ +static int find_the_lowest_level_cache_defined_at_level(MachineState *ms, + int *level_found, + CpuTopologyLevel topo_level) { + + CpuTopologyLevel level; + + level =3D machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1I); + if (level =3D=3D topo_level) { + *level_found =3D 1; + return 1; + } + + level =3D machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L1D); + if (level =3D=3D topo_level) { + *level_found =3D 1; + return 1; + } + + level =3D machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L2); + if (level =3D=3D topo_level) { + *level_found =3D 2; + return 2; + } + + level =3D machine_get_cache_topo_level(ms, CACHE_LEVEL_AND_TYPE_L3); + if (level =3D=3D topo_level) { + *level_found =3D 3; + return 3; + } + + return 0; +} + +static void build_cache_nodes(GArray *tbl, ACPIPPTTCache *cache, + uint32_t next_offset, unsigned int id) +{ + int val; + + /* Type 1 - cache */ + build_append_byte(tbl, 1); + /* Length */ + build_append_byte(tbl, 28); + /* Reserved */ + build_append_int_noprefix(tbl, 0, 2); + /* Flags - everything except possibly the ID */ + build_append_int_noprefix(tbl, 0xff, 4); + /* Offset of next cache up */ + build_append_int_noprefix(tbl, next_offset, 4); + build_append_int_noprefix(tbl, cache->size, 4); + build_append_int_noprefix(tbl, cache->sets, 4); + build_append_byte(tbl, cache->associativity); + val =3D 0x3; + switch (cache->type) { + case INSTRUCTION: + val |=3D (1 << 2); + break; + case DATA: + val |=3D (0 << 2); /* Data */ + break; + case UNIFIED: + val |=3D (3 << 2); /* Unified */ + break; + } + build_append_byte(tbl, val); + build_append_int_noprefix(tbl, cache->linesize, 2); + build_append_int_noprefix(tbl, + (cache->type << 24) | (cache->level << 16) | = id, + 4); +} + +/* + * builds caches from the top level (`level_high` parameter) to the bottom + * level (`level_low` parameter). It searches for caches found in + * systems' registers, and fills up the table. Then it updates the + * `data_offset` and `instr_offset` parameters with the offset of the data + * and instruction caches of the lowest level, respectively. + */ +static bool build_caches(GArray *table_data, uint32_t pptt_start, + int num_caches, ACPIPPTTCache *caches, + int base_id, + uint8_t level_high, /* Inclusive */ + uint8_t level_low, /* Inclusive */ + uint32_t *data_offset, + uint32_t *instr_offset) +{ + uint32_t next_level_offset_data =3D 0, next_level_offset_instruction = =3D 0; + uint32_t this_offset, next_offset =3D 0; + int c, level; + bool found_cache =3D false; + + /* Walk caches from top to bottom */ + for (level =3D level_high; level >=3D level_low; level--) { + for (c =3D 0; c < num_caches; c++) { + if (caches[c].level !=3D level) { + continue; + } + + /* Assume only unified above l1 for now */ + this_offset =3D table_data->len - pptt_start; + switch (caches[c].type) { + case INSTRUCTION: + next_offset =3D next_level_offset_instruction; + break; + case DATA: + next_offset =3D next_level_offset_data; + break; + case UNIFIED: + /* Either is fine here - hopefully */ + next_offset =3D next_level_offset_instruction; + break; + } + build_cache_nodes(table_data, &caches[c], next_offset, base_id= ); + switch (caches[c].type) { + case INSTRUCTION: + next_level_offset_instruction =3D this_offset; + break; + case DATA: + next_level_offset_data =3D this_offset; + break; + case UNIFIED: + next_level_offset_instruction =3D this_offset; + next_level_offset_data =3D this_offset; + break; + } + *data_offset =3D next_level_offset_data; + *instr_offset =3D next_level_offset_instruction; + + found_cache =3D true; + } + } + + return found_cache; +} /* * ACPI spec, Revision 6.3 * 5.2.29.1 Processor hierarchy node structure (Type 0) @@ -2047,24 +2244,40 @@ void build_spcr(GArray *table_data, BIOSLinker *lin= ker, =20 acpi_table_end(linker, &table); } + /* * ACPI spec, Revision 6.3 * 5.2.29 Processor Properties Topology Table (PPTT) */ void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, - const char *oem_id, const char *oem_table_id) + const char *oem_id, const char *oem_table_id, + int num_caches, ACPIPPTTCache *caches) { MachineClass *mc =3D MACHINE_GET_CLASS(ms); CPUArchIdList *cpus =3D ms->possible_cpus; + uint32_t l1_data_offset =3D 0, l1_instr_offset =3D 0, cluster_data_off= set =3D 0; + uint32_t cluster_instr_offset =3D 0, node_data_offset =3D 0; + uint32_t node_instr_offset =3D 0; + int top_node =3D 3, top_cluster =3D 3, top_core =3D 3; + int bottom_node =3D 3, bottom_cluster =3D 3, bottom_core =3D 3; int64_t socket_id =3D -1, cluster_id =3D -1, core_id =3D -1; uint32_t socket_offset =3D 0, cluster_offset =3D 0, core_offset =3D 0; uint32_t pptt_start =3D table_data->len; int n; - AcpiTable table =3D { .sig =3D "PPTT", .rev =3D 2, + uint32_t priv_rsrc[2]; + uint32_t num_priv =3D 0; + bool cache_created; + + AcpiTable table =3D { .sig =3D "PPTT", .rev =3D 3, .oem_id =3D oem_id, .oem_table_id =3D oem_table_id= }; =20 acpi_table_begin(&table, table_data); =20 + n =3D partial_cache_description(ms, caches, num_caches); + if (ms->smp_cache.IsDefined && n) { + error_setg(&error_fatal, "Missing cache description at level %d", = n); + } + /* * This works with the assumption that cpus[n].props.*_id has been * sorted from top to down levels in mc->possible_cpu_arch_ids(). @@ -2077,10 +2290,37 @@ void build_pptt(GArray *table_data, BIOSLinker *lin= ker, MachineState *ms, socket_id =3D cpus->cpus[n].props.socket_id; cluster_id =3D -1; core_id =3D -1; + bottom_node =3D top_node; + num_priv =3D 0; + + if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_SOCKET) && + find_the_lowest_level_cache_defined_at_level(ms, + &bottom_node, + CPU_TOPOLOGY_LEVEL_SOCKET)) { + cache_created =3D build_caches(table_data, pptt_start, + num_caches, caches, + n, top_node, bottom_node, + &node_data_offset, &node_instr_offset); + + if (!cache_created) { + error_setg(&error_fatal, "No caches at levels %d-%d", + top_node, bottom_node); + } + + priv_rsrc[0] =3D node_instr_offset; + priv_rsrc[1] =3D node_data_offset; + + if (node_instr_offset || node_data_offset) { + num_priv =3D node_instr_offset =3D=3D node_data_offset= ? 1 : 2; + } + + top_cluster =3D bottom_node - 1; + } + socket_offset =3D table_data->len - pptt_start; build_processor_hierarchy_node(table_data, (1 << 0), /* Physical package */ - 0, socket_id, NULL, 0); + 0, socket_id, priv_rsrc, num_priv); } =20 if (mc->smp_props.clusters_supported && mc->smp_props.has_clusters= ) { @@ -2088,20 +2328,80 @@ void build_pptt(GArray *table_data, BIOSLinker *lin= ker, MachineState *ms, assert(cpus->cpus[n].props.cluster_id > cluster_id); cluster_id =3D cpus->cpus[n].props.cluster_id; core_id =3D -1; + bottom_cluster =3D top_cluster; + num_priv =3D 0; + + if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CLUSTER) && + find_the_lowest_level_cache_defined_at_level(ms, + &bottom_cluster, + CPU_TOPOLOGY_LEVEL_CLUSTER)) { + + cache_created =3D build_caches(table_data, pptt_start, + num_caches, caches, n, top_cluster, bottom_cluster, + &cluster_data_offset, &cluster_instr_offset); + + if (!cache_created) { + error_setg(&error_fatal, "No caches at levels %d-%= d", + top_cluster, bottom_cluster); + } + + priv_rsrc[0] =3D cluster_instr_offset; + priv_rsrc[1] =3D cluster_data_offset; + + if (cluster_instr_offset || cluster_data_offset) { + num_priv =3D cluster_instr_offset =3D=3D cluster_d= ata_offset ? + 1 : 2; + } + + top_core =3D bottom_cluster - 1; + } else { + top_core =3D bottom_node - 1; + } + cluster_offset =3D table_data->len - pptt_start; build_processor_hierarchy_node(table_data, (0 << 0), /* Not a physical package */ - socket_offset, cluster_id, NULL, 0); + socket_offset, cluster_id, priv_rsrc, num_priv); } } else { + if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CLUSTER)) { + error_setg(&error_fatal, "Not clusters found for the cache= "); + } + cluster_offset =3D socket_offset; + top_core =3D bottom_node - 1; /* there is no cluster */ + } + + if (cpus->cpus[n].props.core_id !=3D core_id) { + bottom_core =3D top_core; + num_priv =3D 0; + + if (cache_described_at(ms, CPU_TOPOLOGY_LEVEL_CORE) && + find_the_lowest_level_cache_defined_at_level(ms, + &bottom_core, + CPU_TOPOLOGY_LEVEL_CORE)) { + cache_created =3D build_caches(table_data, pptt_start, + num_caches, caches, + n, top_core , bottom_core, + &l1_data_offset, &l1_instr_offset); + + if (!cache_created) { + error_setg(&error_fatal, "No cache defined at levels %= d-%d", + top_core, bottom_core); + } + + priv_rsrc[0] =3D l1_instr_offset; + priv_rsrc[1] =3D l1_data_offset; + + num_priv =3D l1_instr_offset =3D=3D l1_data_offset ? 1 : 2; + } } =20 if (ms->smp.threads =3D=3D 1) { build_processor_hierarchy_node(table_data, (1 << 1) | /* ACPI Processor ID valid */ (1 << 3), /* Node is a Leaf */ - cluster_offset, n, NULL, 0); + cluster_offset, n, priv_rsrc, num_priv); } else { if (cpus->cpus[n].props.core_id !=3D core_id) { assert(cpus->cpus[n].props.core_id > core_id); @@ -2109,7 +2409,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linke= r, MachineState *ms, core_offset =3D table_data->len - pptt_start; build_processor_hierarchy_node(table_data, (0 << 0), /* Not a physical package */ - cluster_offset, core_id, NULL, 0); + cluster_offset, core_id, priv_rsrc, num_priv); } =20 build_processor_hierarchy_node(table_data, diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index f76fb117ad..918ed71ccd 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -60,11 +60,14 @@ #include "hw/acpi/acpi_generic_initiator.h" #include "hw/virtio/virtio-acpi.h" #include "target/arm/multiprocessing.h" +#include "cpu-features.h" =20 #define ARM_SPI_BASE 32 =20 #define ACPI_BUILD_TABLE_SIZE 0x20000 =20 +#define ACPI_PPTT_MAX_CACHES 16 + static void acpi_dsdt_add_cpus(Aml *scope, VirtMachineState *vms) { MachineState *ms =3D MACHINE(vms); @@ -890,6 +893,132 @@ static void acpi_align_size(GArray *blob, unsigned al= ign) g_array_set_size(blob, ROUND_UP(acpi_data_len(blob), align)); } =20 +static unsigned int virt_get_caches(VirtMachineState *vms, + ACPIPPTTCache *caches) +{ + ARMCPU *armcpu =3D ARM_CPU(qemu_get_cpu(0)); /* assume homogeneous CPU= s */ + bool ccidx =3D cpu_isar_feature(any_ccidx, armcpu); + unsigned int num_cache, i; + int level_instr =3D 1, level_data =3D 1; + + for (i =3D 0, num_cache =3D 0; i < ACPI_PPTT_MAX_CACHES; i++, num_cach= e++) { + int type =3D (armcpu->clidr >> (3 * i)) & 7; + int bank_index; + int level; + ACPIPPTTCacheType cache_type; + + if (type =3D=3D 0) { + break; + } + + switch (type) { + case 1: + cache_type =3D INSTRUCTION; + level =3D level_instr; + break; + case 2: + cache_type =3D DATA; + level =3D level_data; + break; + case 4: + cache_type =3D UNIFIED; + level =3D level_instr > level_data ? level_instr : level_data; + break; + case 3: /* Split - Do data first */ + cache_type =3D DATA; + level =3D level_data; + break; + default: + error_setg(&error_abort, "Unrecognized cache type"); + return 0; + } + /* + * ccsidr is indexed using both the level and whether it is + * an instruction cache. Unified caches use the same storage + * as data caches. + */ + bank_index =3D (i * 2) | ((type =3D=3D 1) ? 1 : 0); + if (ccidx) { + caches[num_cache] =3D (ACPIPPTTCache) { + .type =3D cache_type, + .level =3D level, + .linesize =3D 1 << (FIELD_EX64(armcpu->ccsidr[bank_index], + CCSIDR_EL1, + CCIDX_LINESIZE) + 4), + .associativity =3D FIELD_EX64(armcpu->ccsidr[bank_index], + CCSIDR_EL1, + CCIDX_ASSOCIATIVITY) + 1, + .sets =3D FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL= 1, + CCIDX_NUMSETS) + 1, + }; + } else { + caches[num_cache] =3D (ACPIPPTTCache) { + .type =3D cache_type, + .level =3D level, + .linesize =3D 1 << (FIELD_EX64(armcpu->ccsidr[bank_index], + CCSIDR_EL1, LINESIZE) + 4), + .associativity =3D FIELD_EX64(armcpu->ccsidr[bank_index], + CCSIDR_EL1, + ASSOCIATIVITY) + 1, + .sets =3D FIELD_EX64(armcpu->ccsidr[bank_index], CCSIDR_EL= 1, + NUMSETS) + 1, + }; + } + caches[num_cache].size =3D caches[num_cache].associativity * + caches[num_cache].sets * caches[num_cache].linesize; + + /* Break one 'split' entry up into two records */ + if (type =3D=3D 3) { + num_cache++; + bank_index =3D (i * 2) | 1; + if (ccidx) { + /* Instruction cache: bottom bit set when reading banked r= eg */ + caches[num_cache] =3D (ACPIPPTTCache) { + .type =3D INSTRUCTION, + .level =3D level_instr, + .linesize =3D 1 << (FIELD_EX64(armcpu->ccsidr[bank_ind= ex], + CCSIDR_EL1, + CCIDX_LINESIZE) + 4), + .associativity =3D FIELD_EX64(armcpu->ccsidr[bank_inde= x], + CCSIDR_EL1, + CCIDX_ASSOCIATIVITY) + 1, + .sets =3D FIELD_EX64(armcpu->ccsidr[bank_index], CCSID= R_EL1, + CCIDX_NUMSETS) + 1, + }; + } else { + caches[num_cache] =3D (ACPIPPTTCache) { + .type =3D INSTRUCTION, + .level =3D level_instr, + .linesize =3D 1 << (FIELD_EX64(armcpu->ccsidr[bank_ind= ex], + CCSIDR_EL1, LINESIZE) + 4= ), + .associativity =3D FIELD_EX64(armcpu->ccsidr[bank_inde= x], + CCSIDR_EL1, + ASSOCIATIVITY) + 1, + .sets =3D FIELD_EX64(armcpu->ccsidr[bank_index], CCSID= R_EL1, + NUMSETS) + 1, + }; + } + caches[num_cache].size =3D caches[num_cache].associativity * + caches[num_cache].sets * caches[num_cache].linesize; + } + switch (type) { + case 1: + level_instr++; + break; + case 2: + level_data++; + break; + case 3: + case 4: + level_instr++; + level_data++; + break; + } + } + + return num_cache; +} + static void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) { @@ -899,6 +1028,11 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuild= Tables *tables) GArray *tables_blob =3D tables->table_data; MachineState *ms =3D MACHINE(vms); =20 + ACPIPPTTCache caches[ACPI_PPTT_MAX_CACHES]; /* Can select up to 16 */ + unsigned int num_cache; + + num_cache =3D virt_get_caches(vms, caches); + table_offsets =3D g_array_new(false, true /* clear */, sizeof(uint32_t)); =20 @@ -920,7 +1054,8 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildT= ables *tables) if (!vmc->no_cpu_topology) { acpi_add_table(table_offsets, tables_blob); build_pptt(tables_blob, tables->linker, ms, - vms->oem_id, vms->oem_table_id); + vms->oem_id, vms->oem_table_id, + num_cache, caches); } =20 acpi_add_table(table_offsets, tables_blob); diff --git a/hw/arm/virt.c b/hw/arm/virt.c index 687fe0bb8b..7944a7616f 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3094,6 +3094,11 @@ static void virt_machine_class_init(ObjectClass *oc,= void *data) hc->unplug =3D virt_machine_device_unplug_cb; mc->nvdimm_supported =3D true; mc->smp_props.clusters_supported =3D true; + /* Supported cached */ + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1D] =3D true; + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L1I] =3D true; + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L2] =3D true; + mc->smp_props.cache_supported[CACHE_LEVEL_AND_TYPE_L3] =3D true; mc->auto_enable_numa_with_memhp =3D true; mc->auto_enable_numa_with_memdev =3D true; /* platform instead of architectural choice */ diff --git a/hw/loongarch/acpi-build.c b/hw/loongarch/acpi-build.c index 2638f87434..4c41be0069 100644 --- a/hw/loongarch/acpi-build.c +++ b/hw/loongarch/acpi-build.c @@ -473,7 +473,8 @@ static void acpi_build(AcpiBuildTables *tables, Machine= State *machine) =20 acpi_add_table(table_offsets, tables_blob); build_pptt(tables_blob, tables->linker, machine, - lvms->oem_id, lvms->oem_table_id); + lvms->oem_id, lvms->oem_table_id, + 0, NULL); =20 acpi_add_table(table_offsets, tables_blob); build_srat(tables_blob, tables->linker, machine); diff --git a/include/hw/acpi/aml-build.h b/include/hw/acpi/aml-build.h index a3784155cb..9077b81ba2 100644 --- a/include/hw/acpi/aml-build.h +++ b/include/hw/acpi/aml-build.h @@ -31,6 +31,23 @@ struct Aml { AmlBlockFlags block_flags; }; =20 +typedef enum ACPIPPTTCacheType { + DATA, + INSTRUCTION, + UNIFIED, +} ACPIPPTTCacheType; + +typedef struct ACPIPPTTCache { + ACPIPPTTCacheType type; + uint32_t pptt_id; + uint32_t sets; + uint32_t size; + uint32_t level; + uint16_t linesize; + uint8_t attributes; /* write policy: 0x0 write back, 0x1 write through= */ + uint8_t associativity; +} ACPIPPTTCache; + typedef enum { AML_COMPATIBILITY =3D 0, AML_TYPEA =3D 1, @@ -490,7 +507,8 @@ void build_slit(GArray *table_data, BIOSLinker *linker,= MachineState *ms, const char *oem_id, const char *oem_table_id); =20 void build_pptt(GArray *table_data, BIOSLinker *linker, MachineState *ms, - const char *oem_id, const char *oem_table_id); + const char *oem_id, const char *oem_table_id, + int num_caches, ACPIPPTTCache *caches); =20 void build_fadt(GArray *tbl, BIOSLinker *linker, const AcpiFadtData *f, const char *oem_id, const char *oem_table_id); --=20 2.34.1