|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v6 5/5] xen/acpi: Parse PPTT to initialize CPU topology
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 threading. For ACPI 6.2 and
earlier, CPUs are assumed not to support threading.
Signed-off-by: Hirokazu Takahashi <taka@xxxxxxxxxxxxx>
---
Changes in v6:
* Handled cases where cluster info is missing upon reaching a physical
package in the PPTT parser by assuming one cluster per socket.
* Enforced an upper limit on the PPTT parsing loop iterations to prevent
infinite loops on corrupted tables.
* Treat the absence of a physical package node definition in PPTT as a
parsing error.
* Added explicit braces `{}` to nested `if` statements to clarify `else`
scoping and maintain style symmetry.
* Enforced an upper limit on the PPTT parsing loop iterations to prevent
infinite loops on corrupted tables.
* Treat the absence of a physical package node definition in PPTT as a
parsing error.
* Dynamically allocate the temporary data storage used during ACPI PPTT
parsing.
* Applied the `static` specifier to file-local data structures and functions.
* Minimized the use of fixed-width `uint32_t` types, restricting its use only
where strictly required by the 32-bit ACPI ID specification.
* Declared `map_cpu_acpiid[]` as static and introduced the helper function
`acpi_map_cpu_acpiid()` for managed access.
* Renamed local variables to more intuitive names.
* Simplified the implementation of `get_logical_id()`.
* Refactored PPTT parsing to reduce type casting by using `container_of()`
and switching from `char *` to `void *` pointers.
* Removed redundant error checks.
* Cleaned up unused variables and eliminated debug print statements.
xen/arch/arm/acpi/boot.c | 2 +
xen/arch/arm/include/asm/acpi.h | 2 +
xen/drivers/acpi/topology.c | 251 ++++++++++++++++++++++++++++++--
xen/include/xen/acpi.h | 2 +
4 files changed, 244 insertions(+), 13 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 56fcfa4945..e6dea527a6 100644
--- a/xen/drivers/acpi/topology.c
+++ b/xen/drivers/acpi/topology.c
@@ -5,32 +5,257 @@
#include <xen/cpumask.h>
#include <xen/init.h>
+#define ACPI_PPTT_MAX_LEVELS 16
+
+static uint32_t __initdata map_cpu_acpiid[NR_CPUS] = {
+ [0 ... NR_CPUS - 1] = INVALID_ACPIID
+};
+
+/*
+ * The first argument `cpu` is the logical CPU ID assigned by Xen,
+ * and the second argument `acpi_id` is passed the `uid` field from
+ * the ACPI MADT Generic Interrupt subtable.
+ */
+void __init acpi_map_cpu_acpiid(unsigned int cpu, uint32_t acpi_id)
+{
+ map_cpu_acpiid[cpu] = acpi_id;
+}
+
+static unsigned int __init get_logical_id(unsigned int key,
+ unsigned int *map,
+ unsigned int *count)
+{
+ unsigned int id;
+
+ for ( id = 0; id < *count; id++ )
+ if ( map[id] == key )
+ return id;
+
+ map[*count] = key;
+
+ return (*count)++;
+}
+
+static const struct acpi_pptt_processor *__init find_pptt_node(
+ const struct acpi_table_pptt *pptt, uint32_t acpi_id)
+{
+ const struct acpi_subtable_header *entry;
+ unsigned long table_end;
+ const void *ptr;
+
+ BUG_ON(!pptt);
+
+ table_end = (unsigned long)pptt + pptt->header.length;
+
+ ptr = pptt + 1;
+
+ while ( (unsigned long)ptr + sizeof(struct acpi_subtable_header)
+ <= table_end )
+ {
+ entry = 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 &&
+ entry->length >= sizeof(struct acpi_pptt_processor) )
+ {
+ const struct acpi_pptt_processor *proc =
+ container_of(entry, const struct acpi_pptt_processor, header);
+
+ if ( (proc->flags & ACPI_PPTT_ACPI_PROCESSOR_ID_VALID) &&
+ proc->acpi_processor_id == acpi_id )
+ return proc;
+ }
+
+ ptr += entry->length;
+ }
+
+ return NULL;
+}
+
/*
- * TODO: Populate the topology information by scanning the ACPI
- * PPTT (Processor Properties Topology Table).
+ * Populate the topology information by scanning the ACPI PPTT
+ * (Processor Properties Topology Table).
*/
int __init acpi_init_cpu_topology(void)
{
+ acpi_status status;
+ struct acpi_table_header *table_header;
+ const struct acpi_table_pptt *pptt;
+ unsigned int num_sockets = 0;
+ unsigned int num_clusters = 0;
+ unsigned int num_cores = 0;
+ unsigned int *socket_map = xmalloc_array(unsigned int, nr_cpu_ids);
+ unsigned int *cluster_map = xmalloc_array(unsigned int, nr_cpu_ids);
+ unsigned int *core_map = xmalloc_array(unsigned int, nr_cpu_ids);
unsigned int cpu;
+ int ret = 0;
+
+ if ( !socket_map || !cluster_map || !core_map )
+ {
+ printk(XENLOG_ERR
+ "ACPI: Failed to allocate memory for topology parsing.\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ status = acpi_get_table(ACPI_SIG_PPTT, 0, &table_header);
+ if ( ACPI_FAILURE(status) )
+ {
+ printk(XENLOG_WARNING
+ "ACPI: PPTT table not found. Topology fallback will be
used.\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ pptt = container_of(table_header, const struct acpi_table_pptt, header);
- /*
- * Generate temporary cpu topology information for now.
- * It assumes that the cpu doesn't have SMT and all CPUs
- * belong to the same socket.
- */
for_each_possible_cpu(cpu)
{
+ uint32_t acpi_id = map_cpu_acpiid[cpu];
struct cpu_topology *topo = &cpu_topology[cpu];
+ const struct acpi_pptt_processor *proc;
+ unsigned int level;
+ unsigned int core_group_key = 0;
+ unsigned int cluster_group_key = 0;
+ unsigned int socket_group_key = 0;
+ bool threading = false;
+
+ proc = find_pptt_node(pptt, acpi_id);
+ if ( !proc )
+ {
+ printk(XENLOG_WARNING
+ "ACPI: No PPTT leaf node for CPU %u (ACPI ID 0x%u)\n",
+ cpu, acpi_id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ /*
+ * Limit the maximum loop depth to prevent an infinite loop in case
+ * the PPTT is corrupted or contains cyclic references.
+ */
+ for ( level = 0; level < ACPI_PPTT_MAX_LEVELS; level++ )
+ {
+ const unsigned int offset = (const void *)proc - (const void
*)pptt;
+
+ if ( proc->flags & ACPI_PPTT_PHYSICAL_PACKAGE )
+ {
+ socket_group_key = offset;
+
+ /*
+ * If cluster/core info is absent upon reaching the physical
+ * package, assume one cluster per socket and one core per
+ * cluster.
+ */
+ if ( cluster_group_key == 0 )
+ cluster_group_key = socket_group_key;
+
+ if ( core_group_key == 0 )
+ core_group_key = cluster_group_key;
+
+ break;
+ }
+ else if ( level == 0 )
+ {
+ /*
+ * ACPI_PPTT_PROCESSOR_IS_THREAD is supported in PPTT
+ * revision 2 and later. Assume no threading support when
+ * PPTT revision is 1.
+ */
+ if ( proc->flags & ACPI_PPTT_ACPI_PROCESSOR_IS_THREAD )
+ threading = true;
+ else
+ core_group_key = offset;
+ }
+ else if ( level == 1 )
+ {
+ if ( threading )
+ core_group_key = offset;
+ else
+ cluster_group_key = offset;
+ }
+ else if ( level == 2 && threading )
+ {
+ cluster_group_key = offset;
+ }
+
+ if ( !proc->parent )
+ break;
- topo->phys_core_id = cpu;
- topo->num_siblings = 1;
+ proc = (const struct acpi_pptt_processor *)
+ ((const void *)pptt + proc->parent);
+ }
- cpumask_set_cpu(cpu, topo->thread_sibling);
- cpumask_copy(topo->core_sibling, &cpu_possible_map);
- cpumask_copy(topo->cluster_sibling, &cpu_possible_map);
+ if ( socket_group_key == 0 )
+ {
+ printk(XENLOG_WARNING
+ "ACPI: Could not reach the physical package node for CPU %u
(ACPI ID 0x%u)\n",
+ cpu, acpi_id);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ topo->phys_socket_id =
+ get_logical_id(socket_group_key, socket_map, &num_sockets);
+ topo->phys_cluster_id =
+ get_logical_id(cluster_group_key, cluster_map, &num_clusters);
+ topo->phys_core_id =
+ get_logical_id(core_group_key, core_map, &num_cores);
}
- return 0;
+ 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);
+ }
+
+out:
+ xfree(socket_map);
+ xfree(cluster_map);
+ xfree(core_map);
+
+ return ret;
}
/*
diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
index cbb02e0f35..d2a1531893 100644
--- a/xen/include/xen/acpi.h
+++ b/xen/include/xen/acpi.h
@@ -137,10 +137,12 @@ static inline int acpi_boot_table_init(void)
#ifdef CONFIG_ACPI_CPU_TOPOLOGY
+void acpi_map_cpu_acpiid(unsigned int cpu, uint32_t acpi_id);
int acpi_init_cpu_topology(void);
#else /* CONFIG_ACPI_CPU_TOPOLOGY */
+static inline void acpi_map_cpu_acpiid(unsigned int cpu, uint32_t acpi_id) {}
static inline int acpi_init_cpu_topology(void)
{
return -EOPNOTSUPP;
--
2.43.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |