From nobody Mon Apr 6 09:27:48 2026 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=1773245614; cv=none; d=zohomail.com; s=zohoarc; b=O2yUbSHHmAtJS9qhWtzzaz0G5Ohhs0ci6zOy0BI0JI7GH6J/HWmjKfljJvtOzzAROpaGT+vaFl9VNlIl89sdSiQvKq7ZKHL0b7fyv0xMMM2PaYDSIx5Lq05NU0uaFDQbI5Cgi++zgAiBA+mW5WK+ijToiq1gGiQQo3p2PY3KAeY= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1773245614; 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=sipKZvifoTuvdSnhGEWf0FIyMyCOGa/uynuO39zVj+s=; b=RKuA9wAWNTOMkRf0CwOaETVbsnwZsDmHnt53My6o4LriZckqXP0b8UMnxjgSEhtOTQLolIXGhLwV6swHOYRhSC7m8yzCsX61quiF8AOxqDxOZSVMTDulOc9SXWQqxemDsd2fNd0ctDBZlKZtx0calrdfC0kQzYILOrODuSawBOY= 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 1773245614616122.32415049755593; Wed, 11 Mar 2026 09:13:34 -0700 (PDT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1w0M8Q-0007p8-66; Wed, 11 Mar 2026 12:10:10 -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 1w0M7w-0007O8-OT; Wed, 11 Mar 2026 12:09:41 -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 1w0M7s-0007KK-Jt; Wed, 11 Mar 2026 12:09:39 -0400 Received: from mail.maildlp.com (unknown [172.18.224.83]) by frasgout.his.huawei.com (SkyGuard) with ESMTPS id 4fWG0K3MsfzHnGd0; Thu, 12 Mar 2026 00:09:21 +0800 (CST) Received: from dubpeml500005.china.huawei.com (unknown [7.214.145.207]) by mail.maildlp.com (Postfix) with ESMTPS id 6AE0240569; Thu, 12 Mar 2026 00:09:29 +0800 (CST) Received: from a2303103017.china.huawei.com (10.203.177.99) by dubpeml500005.china.huawei.com (7.214.145.207) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1544.11; Wed, 11 Mar 2026 16:09:28 +0000 To: , , CC: , , , , , , , , , , , , , , , , , Subject: [PATCH v19 6/8] hw/acpi: add cache hierarchy to pptt table Date: Wed, 11 Mar 2026 16:06:06 +0000 Message-ID: <20260311160609.358-7-alireza.sanaee@huawei.com> X-Mailer: git-send-email 2.51.0.windows.2 In-Reply-To: <20260311160609.358-1-alireza.sanaee@huawei.com> References: <20260311160609.358-1-alireza.sanaee@huawei.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Originating-IP: [10.203.177.99] X-ClientProxiedBy: lhrpeml500009.china.huawei.com (7.191.174.84) To dubpeml500005.china.huawei.com (7.214.145.207) 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: -24 X-Spam_score: -2.5 X-Spam_bar: -- X-Spam_report: (-2.5 / 5.0 requ) BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.819, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.903, 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: qemu development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-to: Alireza Sanaee From: Alireza Sanaee via qemu development Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: qemu-devel-bounces+importer=patchew.org@nongnu.org X-ZM-MESSAGEID: 1773245615971154100 Content-Type: text/plain; charset="utf-8" Add cache topology to PPTT table. Signed-off-by: Alireza Sanaee Reviewed-by: Gustavo Romero --- Thanks for the review Gustavo. Change log: v18->v19: - Fixed some comments. - Removed the extra check on existence of cache at the topology l= evel in build_pptt function since it is already checked in=20 machine_find_lowest_level_cache_at_topo_level function. hw/acpi/aml-build.c | 200 +++++++++++++++++++++++++++++++++++++-- hw/arm/virt-acpi-build.c | 8 +- include/hw/acpi/cpu.h | 10 ++ 3 files changed, 209 insertions(+), 9 deletions(-) diff --git a/hw/acpi/aml-build.c b/hw/acpi/aml-build.c index b0ea8a5d5d..7edc8aed42 100644 --- a/hw/acpi/aml-build.c +++ b/hw/acpi/aml-build.c @@ -34,6 +34,7 @@ #include "hw/pci/pci_bridge.h" #include "hw/acpi/acpi_aml_interface.h" #include "qemu/cutils.h" +#include "hw/core/cpu.h" =20 static GArray *build_alloc_array(void) { @@ -2150,6 +2151,108 @@ void build_spcr(GArray *table_data, BIOSLinker *lin= ker, } acpi_table_end(linker, &table); } + +/* + * ACPI spec, Revision 6.3 + * 5.2.29.2 Cache Type Structure (Type 1) + */ +static void build_cache_nodes(GArray *tbl, CPUCoreCaches *cache, + uint32_t next_offset) +{ + const uint8_t node_length =3D 24; + int start_len =3D tbl->len; + int val; + + build_append_byte(tbl, 1); /* Type 1 - cache */ + build_append_byte(tbl, node_length); /* Length */ + build_append_int_noprefix(tbl, 0, 2); /* Reserved */ + build_append_int_noprefix(tbl, 0x7f, 4); /* Flags */ + build_append_int_noprefix(tbl, next_offset, 4); /* Next Level of Ca= che */ + build_append_int_noprefix(tbl, cache->size, 4); /* Size */ + build_append_int_noprefix(tbl, cache->sets, 4); /* Number of sets */ + build_append_byte(tbl, cache->associativity); /* Associativity */ + val =3D 0x3; + switch (cache->type) { + case INSTRUCTION_CACHE: + val |=3D (1 << 2); /* Instruction Cache */ + break; + case DATA_CACHE: + val |=3D (0 << 2); /* Data Cache */ + break; + case UNIFIED_CACHE: + val |=3D (3 << 2); /* Unified */ + break; + } + build_append_byte(tbl, val); /* Attributes */ + build_append_int_noprefix(tbl, cache->linesize, 2); /* Line size */ + g_assert(tbl->len =3D=3D start_len + node_length); +} + +/* + * Build PPTT Cache Type structures (Type 1) from cache level `level_high` + * down to `level_low` (both inclusive), appending them to the PPTT table. + * + * On output, `data_offset` and `instr_offset` hold the PPTT offsets of the + * lowest-level data and instruction cache nodes respectively. These offs= ets + * are referenced as private resources in the Processor Hierarchy Node (Ty= pe 0) + * that owns the caches. + */ +static bool build_caches(GArray *table_data, uint32_t pptt_start, + int num_caches, CPUCoreCaches *caches, + 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_CACHE: + next_offset =3D next_level_offset_instruction; + break; + case DATA_CACHE: + next_offset =3D next_level_offset_data; + break; + case UNIFIED_CACHE: + /* Either is fine here */ + next_offset =3D next_level_offset_instruction; + break; + } + build_cache_nodes(table_data, &caches[c], next_offset); + switch (caches[c].type) { + case INSTRUCTION_CACHE: + next_level_offset_instruction =3D this_offset; + break; + case DATA_CACHE: + next_level_offset_data =3D this_offset; + break; + case UNIFIED_CACHE: + 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 Processor Properties Topology Table (PPTT) @@ -2160,11 +2263,31 @@ void build_pptt(GArray *table_data, BIOSLinker *lin= ker, MachineState *ms, { MachineClass *mc =3D MACHINE_GET_CLASS(ms); CPUArchIdList *cpus =3D ms->possible_cpus; - 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 core_data_offset =3D 0; + uint32_t core_instr_offset =3D 0; + uint32_t cluster_instr_offset =3D 0; + uint32_t cluster_data_offset =3D 0; + uint32_t node_data_offset =3D 0; + uint32_t node_instr_offset =3D 0; + int top_node =3D 3; + int top_cluster =3D 3; + int top_core =3D 3; + int bottom_node =3D 3; + int bottom_cluster =3D 3; + int bottom_core =3D 3; + int64_t socket_id =3D -1; + int64_t cluster_id =3D -1; + int64_t core_id =3D -1; + uint32_t socket_offset =3D 0; + uint32_t cluster_offset =3D 0; + uint32_t core_offset =3D 0; uint32_t pptt_start =3D table_data->len; uint32_t root_offset; int n; + uint32_t priv_rsrc[2]; + uint32_t num_priv =3D 0; + bool cache_at_topo_level; + AcpiTable table =3D { .sig =3D "PPTT", .rev =3D 2, .oem_id =3D oem_id, .oem_table_id =3D oem_table_id= }; =20 @@ -2194,11 +2317,29 @@ 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; + cache_at_topo_level =3D + machine_find_lowest_level_cache_at_topo_level( + ms, &bottom_node, CPU_TOPOLOGY_LEVEL_SOCKET); + if (cache_at_topo_level) { + build_caches(table_data, pptt_start, num_caches, caches, + top_node, bottom_node, &node_data_offset, + &node_instr_offset); + 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 */ (1 << 4), /* Identical Implementation */ - root_offset, socket_id, NULL, 0); + root_offset, socket_id, priv_rsrc, num_priv); } =20 if (mc->smp_props.clusters_supported && mc->smp_props.has_clusters= ) { @@ -2206,21 +2347,66 @@ 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; + cache_at_topo_level =3D + machine_find_lowest_level_cache_at_topo_level( + ms, &bottom_cluster, CPU_TOPOLOGY_LEVEL_CLUSTER); + + if (cache_at_topo_level) { + build_caches(table_data, pptt_start, num_caches, cache= s, + top_cluster, bottom_cluster, + &cluster_data_offset, &cluster_instr_offs= et); + 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_data_offse= t ? 1 : 2; + } + top_core =3D bottom_cluster - 1; + } else if (top_cluster =3D=3D bottom_node - 1) { + /* socket cache but no cluster cache */ + 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 */ (1 << 4), /* Identical Implementation */ - socket_offset, cluster_id, NULL, 0); + socket_offset, cluster_id, priv_rsrc, num_priv); } } else { + if (machine_defines_cache_at_topo_level( + ms, CPU_TOPOLOGY_LEVEL_CLUSTER)) { + error_setg(&error_fatal, "Not clusters found for the cache= "); + return; + } + 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; + cache_at_topo_level =3D + machine_find_lowest_level_cache_at_topo_level( + ms, &bottom_core, CPU_TOPOLOGY_LEVEL_CORE); + if (cache_at_topo_level) { + build_caches(table_data, pptt_start, num_caches, caches, + top_core, bottom_core, &core_data_offset, + &core_instr_offset); + priv_rsrc[0] =3D core_instr_offset; + priv_rsrc[1] =3D core_data_offset; + num_priv =3D core_instr_offset =3D=3D core_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); + (1 << 3), /* Node is a Leaf */ + 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); @@ -2229,7 +2415,7 @@ void build_pptt(GArray *table_data, BIOSLinker *linke= r, MachineState *ms, build_processor_hierarchy_node(table_data, (0 << 0) | /* Not a physical package */ (1 << 4), /* Identical Implementation */ - 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 3fff78bcca..b230ea2c8e 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -1255,6 +1255,10 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuil= dTables *tables) unsigned dsdt, xsdt; GArray *tables_blob =3D tables->table_data; MachineState *ms =3D MACHINE(vms); + CPUCoreCaches caches[CPU_MAX_CACHES]; + unsigned int num_caches; + + num_caches =3D virt_get_caches(vms, caches); =20 table_offsets =3D g_array_new(false, true /* clear */, sizeof(uint32_t)); @@ -1276,8 +1280,8 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuild= Tables *tables) =20 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, 0, NULL); + build_pptt(tables_blob, tables->linker, ms, vms->oem_id, + vms->oem_table_id, num_caches, caches); } =20 acpi_add_table(table_offsets, tables_blob); diff --git a/include/hw/acpi/cpu.h b/include/hw/acpi/cpu.h index 2809dd8a91..04c821d2b9 100644 --- a/include/hw/acpi/cpu.h +++ b/include/hw/acpi/cpu.h @@ -69,6 +69,16 @@ void build_cpus_aml(Aml *table, MachineState *machine, C= PUHotplugFeatures opts, =20 void acpi_cpu_ospm_status(CPUHotplugState *cpu_st, ACPIOSTInfoList ***list= ); =20 +struct CPUPPTTCaches { + enum CacheType type; + 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; +}; + extern const VMStateDescription vmstate_cpu_hotplug; #define VMSTATE_CPU_HOTPLUG(cpuhp, state) \ VMSTATE_STRUCT(cpuhp, state, 1, \ --=20 2.43.0