[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v5 4/4] arm/acpi: Parse PPTT to initialize CPU topology


  • To: xen-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Hirokazu Takahashi <taka@xxxxxxxxxxxxx>
  • Date: Fri, 10 Jul 2026 07:05:52 +0900
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=valinux.co.jp; dmarc=pass action=none header.from=valinux.co.jp; dkim=pass header.d=valinux.co.jp; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=hHLTHYhQn87WMtZCHSNKRQZGN/vrbyKKjK5gg/fIUwM=; b=LZzMdticrHg73welDCuh5e6QS9uQ/zk3m4ztyWudKSAI8nhQbt7da3V3LC5L6fZf9eFRMUSuWlUjoLeryFj1kkxyTOglIg27h4sVRNIqw7tKGxngGLV0DzZ1vG62XaJO4z80/gVgmtXjlHBKOFsIUBrOl81wbNnkDvpTg8rmX5mgo5Vfx4/NhahuTgrdg+MPV+sdElys8O15ypftQ8R8YMYZa1T+Zl5PkWQkh3U8UwfHLBKgj0jy3xxtpycsbEFPkjxq31tB2Gx4zJirPsTZtqH6UktYV9xdksn5Q1QrZDo1p8gKLvlQpkBnjYZs8uXD94h9BnEsRGBd3ucS7boLxw==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=hxdBvyqKdu3QD+lJKCFPtK7hPdssa6jgwtf/7Obes6NK5T+C8h7jBmE1H1nz+imGppnCRPhTyDsu1dyVfFxkmFQjbtqYm+DeGVzwdE2EZtjXvbfhe7D9Z+/jBYHAph6i354xOlQbMTyxbfPwFYCCwIrg1j/ap14xV9kkvDBPW4tZUtdW8c6b1ItiR6je1W/P/HFeYv/9p9MdmwtaQQK/qp6Mar49cQVslUz85NSIqF+Xzc9dcADctTQhqOQE+XQ00ncccfmiy4JmUn0tsQ0zLvr7LVW+RPqA1vio43FpKbdAkTJtYrYs4QwL3j2mTViyVw7Jp6MvkQQTDHitglds+g==
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=selector1 header.d=valinux.co.jp header.i="@valinux.co.jp" header.h="From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck"
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=valinux.co.jp;
  • Cc: Hirokazu Takahashi <taka@xxxxxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, Julien Grall <julien@xxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, Anthony PERARD <anthony.perard@xxxxxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Roger Pau Monné <roger.pau@xxxxxxxxxx>
  • Delivery-date: Thu, 09 Jul 2026 22:06:37 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Parse the ACPI PPTT (Processor Properties Topology Table) to
initialize the CPU topology.

For ACPI 6.3 and later, the ACPI_PPTT_ACPI_PROCESSOR_IS_THREAD flag
is checked to determine the presence of SMT. For ACPI 6.2 and
earlier, CPUs are assumed not to support SMT.

Signed-off-by: Hirokazu Takahashi <taka@xxxxxxxxxxxxx>
---
Changes in v5:
  Extracted CPU topology information from the ACPI PPTT.

 xen/arch/arm/acpi/boot.c        |   2 +
 xen/arch/arm/include/asm/acpi.h |   2 +
 xen/drivers/acpi/topology.c     | 230 ++++++++++++++++++++++++++++++--
 xen/include/acpi/actbl3.h       |  30 +++++
 xen/include/xen/acpi.h          |   8 ++
 5 files changed, 264 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/acpi/boot.c b/xen/arch/arm/acpi/boot.c
index 4ac0fd8f51..fc7ecb5749 100644
--- a/xen/arch/arm/acpi/boot.c
+++ b/xen/arch/arm/acpi/boot.c
@@ -85,6 +85,7 @@ acpi_map_gic_cpu_interface(struct acpi_madt_generic_interrupt 
*processor)
             return;
         }
         bootcpu_valid = true;
+        acpi_map_cpu_acpiid(0, processor->uid);
         return;
     }
 
@@ -119,6 +120,7 @@ acpi_map_gic_cpu_interface(struct 
acpi_madt_generic_interrupt *processor)
 
     /* map the logical cpu id to cpu MPIDR */
     cpu_logical_map(enabled_cpus) = mpidr;
+    acpi_map_cpu_acpiid(enabled_cpus, processor->uid);
 
     enabled_cpus++;
 }
diff --git a/xen/arch/arm/include/asm/acpi.h b/xen/arch/arm/include/asm/acpi.h
index 13756dd341..b2e156e131 100644
--- a/xen/arch/arm/include/asm/acpi.h
+++ b/xen/arch/arm/include/asm/acpi.h
@@ -61,6 +61,8 @@ paddr_t acpi_get_table_offset(struct membank tbl_add[], 
EFI_MEM_RES index);
     (!(entry) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||  \
      (entry)->header.length != ACPI_MADT_GICC_LENGTH)
 
+#define INVALID_ACPIID         (-1U)
+
 #ifdef CONFIG_ACPI
 extern bool acpi_disabled;
 /* Basic configuration for ACPI */
diff --git a/xen/drivers/acpi/topology.c b/xen/drivers/acpi/topology.c
index 9155edc0be..37e7c70625 100644
--- a/xen/drivers/acpi/topology.c
+++ b/xen/drivers/acpi/topology.c
@@ -5,18 +5,90 @@
 #include <xen/cpumask.h>
 #include <xen/init.h>
 
-/*
- * TODO: Populate the topology information by scanning the ACPI
- *       PPTT (Processor Properties Topology Table).
- */
-void __init acpi_init_cpu_topology(void)
+uint32_t map_cpu_acpiid[NR_CPUS] __initdata =
+         { [0 ... NR_CPUS - 1] = INVALID_ACPIID };
+uint32_t socket_map[NR_CPUS] __initdata;
+uint32_t cluster_map[NR_CPUS] __initdata;
+uint32_t core_map[NR_CPUS] __initdata;
+uint32_t thread_map[NR_CPUS] __initdata;
+unsigned int __initdata num_sockets;
+unsigned int __initdata num_clusters;
+unsigned int __initdata num_cores;
+
+static unsigned int __init get_logical_id(uint32_t phys_offset,
+                                          uint32_t *map,
+                                          unsigned int *count)
+{
+    unsigned int id;
+
+    for ( id = 0; id < *count; id++ )
+        if ( map[id] == phys_offset )
+            return id;
+
+    map[*count] = phys_offset;
+    id = *count;
+    (*count)++;
+
+    return id;
+}
+
+static struct acpi_pptt_processor *__init find_pptt_node(
+       const struct acpi_table_header *table_hdr, unsigned int acpi_id)
+{
+    const struct acpi_subtable_header *entry;
+    unsigned long table_end;
+    const char *ptr;
+
+    if ( !table_hdr )
+        return NULL;
+
+    table_end = (unsigned long)table_hdr + table_hdr->length;
+
+    ptr = (const char *)table_hdr + sizeof(struct acpi_table_pptt);
+
+    while ( (unsigned long)ptr + sizeof(struct acpi_subtable_header)
+            <= table_end )
+    {
+        entry = (const struct acpi_subtable_header *)ptr;
+
+        if ( entry->length == 0 )
+        {
+            printk(XENLOG_ERR
+                   "ACPI: PPTT has an invalid zero-length subtable.\n");
+            break;
+        }
+
+        if ( (unsigned long)ptr + entry->length > table_end )
+        {
+            printk(XENLOG_ERR
+                   "ACPI: PPTT subtable extends beyond table end.\n");
+            break;
+        }
+
+        if ( entry->type == ACPI_PPTT_TYPE_PROCESSOR )
+            if ( entry->length >= sizeof(struct acpi_pptt_processor) )
+            {
+                struct acpi_pptt_processor *proc =
+                       (struct acpi_pptt_processor *)entry;
+
+                if ( (proc->flags & ACPI_PPTT_ACPI_PROCESSOR_ID_VALID) &&
+                     proc->acpi_processor_id == acpi_id )
+                    return proc;
+            }
+
+        ptr += entry->length;
+    }
+
+    return NULL;
+}
+
+static void __init setup_fake_topology(void)
 {
     unsigned int cpu;
 
     /*
-     * Generate temporary cpu topology information for now.
-     * It assumes that the cpu doesn't have SMT and all CPUs
-     * belong to the same socket.
+     * Generate temporary cpu topology information. It assumes that
+     * the cpu doesn't have SMT and all CPUs belong to the same socket.
      */
     for_each_possible_cpu(cpu)
     {
@@ -30,6 +102,148 @@ void __init acpi_init_cpu_topology(void)
     }
 }
 
+/*
+ * Populate the topology information by scanning the ACPI PPTT
+ * (Processor Properties Topology Table).
+ */
+void __init acpi_init_cpu_topology(void)
+{
+    acpi_status status;
+    struct acpi_table_header *header;
+    const struct acpi_table_pptt *pptt;
+    unsigned int cpu;
+
+    status = acpi_get_table(ACPI_SIG_PPTT, 0, &header);
+    if ( ACPI_FAILURE(status) )
+    {
+        printk(XENLOG_WARNING
+               "ACPI: PPTT table not found. Topology fallback will be 
used.\n");
+        setup_fake_topology();
+        return;
+    }
+
+    pptt = (struct acpi_table_pptt *)header;
+
+    for_each_possible_cpu(cpu)
+    {
+        unsigned int acpi_id = map_cpu_acpiid[cpu];
+        struct cpu_topology *topo = &cpu_topology[cpu];
+        const struct acpi_pptt_processor *proc;
+        unsigned int level = 0;
+        uint32_t thread_offset = 0;
+        uint32_t core_offset = 0;
+        uint32_t cluster_offset = 0;
+        uint32_t socket_offset = 0;
+        bool threading = true;
+
+        proc = find_pptt_node(&pptt->header, acpi_id);
+        if ( !proc )
+        {
+            printk(XENLOG_WARNING
+                   "ACPI: No PPTT leaf node for CPU %u (ACPI ID 0x%u)\n",
+                   cpu, acpi_id);
+            continue;
+        }
+
+        while ( proc )
+        {
+            if ( proc->flags & ACPI_PPTT_PHYSICAL_PACKAGE )
+            {
+                socket_offset = (char *)proc - (char *)pptt;
+                break;
+            }
+            else if ( level == 0 )
+                /*
+                 * ACPI_PPTT_PROCESSOR_IS_THREAD is supported in PPTT
+                 * revision 2 and later.
+                 */
+                if ( proc->flags & ACPI_PPTT_ACPI_PROCESSOR_IS_THREAD )
+                    thread_offset = (char *)proc - (char *)pptt;
+                else
+                {
+                    /* Assume no threading support when PPTT revision is 1. */
+                    threading = false;
+                    core_offset = (char *)proc - (char *)pptt;
+                }
+            else if ( level == 1 )
+                if ( threading )
+                    core_offset = (char *)proc - (char *)pptt;
+                else
+                    cluster_offset = (char *)proc - (char *)pptt;
+            else if ( level == 2 )
+                if ( threading )
+                    cluster_offset = (char *)proc - (char *)pptt;
+
+            if ( proc->parent )
+            {
+                proc = (const struct acpi_pptt_processor *)
+                       ((char *)pptt + proc->parent);
+                level++;
+            }
+            else
+                break;
+        }
+
+        topo->phys_socket_id =
+            get_logical_id(socket_offset, socket_map, &num_sockets);
+        topo->phys_cluster_id =
+            get_logical_id(cluster_offset, cluster_map, &num_clusters);
+        topo->phys_core_id =
+            get_logical_id(core_offset, core_map, &num_cores);
+
+        /* Fall back to socket ID if PPTT lacks cluster information. */
+        if ( topo->phys_cluster_id == 0 )
+            topo->phys_cluster_id = topo->phys_socket_id;
+    }
+
+    for_each_possible_cpu(cpu)
+    {
+        struct cpu_topology *topo = &cpu_topology[cpu];
+        unsigned int tcpu;
+
+        for_each_possible_cpu(tcpu)
+        {
+            struct cpu_topology *ttopo = &cpu_topology[tcpu];
+
+            if ( cpu > tcpu )
+                continue;
+
+            if ( topo->phys_core_id == ttopo->phys_core_id )
+            {
+                cpumask_set_cpu(tcpu, topo->thread_sibling);
+                cpumask_set_cpu(cpu, ttopo->thread_sibling);
+            }
+
+            if ( topo->phys_cluster_id == ttopo->phys_cluster_id )
+            {
+                cpumask_set_cpu(tcpu, topo->cluster_sibling);
+                cpumask_set_cpu(cpu, ttopo->cluster_sibling);
+            }
+
+            if ( topo->phys_socket_id == ttopo->phys_socket_id )
+            {
+                cpumask_set_cpu(tcpu, topo->core_sibling);
+                cpumask_set_cpu(cpu, ttopo->core_sibling);
+            }
+        }
+
+        topo->num_siblings = cpumask_weight(topo->thread_sibling);
+    }
+
+    for_each_possible_cpu(cpu)
+    {
+        const struct cpu_topology *topo = &cpu_topology[cpu];
+
+        printk(XENLOG_DEBUG
+               "ACPI: acpi_id[%u] CPU-%u Socket-%u Cluster-%u Core-%u\n",
+               map_cpu_acpiid[cpu],
+               cpu,
+               topo->phys_socket_id,
+               topo->phys_cluster_id,
+               topo->phys_core_id);
+    }
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/include/acpi/actbl3.h b/xen/include/acpi/actbl3.h
index 636d3f5f5b..48907d0532 100644
--- a/xen/include/acpi/actbl3.h
+++ b/xen/include/acpi/actbl3.h
@@ -72,6 +72,7 @@
 
 #define ACPI_SIG_S3PT           "S3PT" /* S3 Performance (sub)Table */
 #define ACPI_SIG_PCCS           "PCC"  /* PCC Shared Memory Region */
+#define ACPI_SIG_PPTT           "PPTT" /* Processor Properties Topology Table 
*/
 
 /* Reserved table signatures */
 
@@ -637,6 +638,35 @@ struct acpi_table_stao {
        u8 ignore_uart;
 };
 
+/*******************************************************************************
+ *
+ * PPTT - Processor Properties Topology Table - ACPI 6.3
+ *        Version 1
+ *
+ 
******************************************************************************/
+struct acpi_table_pptt {
+    struct acpi_table_header header;
+};
+
+#define ACPI_PPTT_TYPE_PROCESSOR            0
+#define ACPI_PPTT_TYPE_CACHE                1
+#define ACPI_PPTT_TYPE_ID                   2
+
+struct acpi_pptt_processor {
+    struct acpi_subtable_header header;
+    u16 reserved;
+    u32 flags;
+    u32 parent;
+    u32 acpi_processor_id;
+    u32 number_of_priv_resources;
+};
+
+#define ACPI_PPTT_PHYSICAL_PACKAGE          (1)
+#define ACPI_PPTT_ACPI_PROCESSOR_ID_VALID   (1 << 1)
+#define ACPI_PPTT_ACPI_PROCESSOR_IS_THREAD  (1 << 2)  /* ACPI 6.3 */
+#define ACPI_PPTT_ACPI_LEAF_NODE            (1 << 3)  /* ACPI 6.3 */
+#define ACPI_PPTT_ACPI_IDENTICAL            (1 << 4)  /* ACPI 6.3 */
+
 /* Reset to default packing */
 
 #pragma pack()
diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
index bd982ee836..e717f36151 100644
--- a/xen/include/xen/acpi.h
+++ b/xen/include/xen/acpi.h
@@ -139,8 +139,16 @@ static inline int acpi_boot_table_init(void)
 
 void acpi_init_cpu_topology(void);
 
+extern uint32_t map_cpu_acpiid[NR_CPUS];
+
+static inline void acpi_map_cpu_acpiid(unsigned int cpu, uint32_t acpi_id)
+{
+    map_cpu_acpiid[cpu] = acpi_id;
+}
+
 #else /* CONFIG_ACPI_CPU_TOPOLOGY */
 
+static inline void acpi_map_cpu_acpiid(unsigned int cpu, uint32_t acpi_id) {}
 static inline void acpi_init_cpu_topology(void) {}
 
 #endif /* CONFIG_ACPI_CPU_TOPOLOGY */
-- 
2.43.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.