]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
arm64: topology: Support SMT control on ACPI based system
authorYicong Yang <yangyicong@hisilicon.com>
Tue, 11 Mar 2025 07:51:42 +0000 (15:51 +0800)
committerCatalin Marinas <catalin.marinas@arm.com>
Fri, 14 Mar 2025 17:31:05 +0000 (17:31 +0000)
For ACPI we'll build the topology from PPTT and we cannot directly
get the SMT number of each core. Instead using a temporary xarray
to record the heterogeneous information (from ACPI_PPTT_ACPI_IDENTICAL)
and SMT information of the first core in its heterogeneous CPU cluster
when building the topology. Then we can know the largest SMT number
in the system. If a homogeneous system's using ACPI 6.2 or later,
all the CPUs should be under the root node of PPTT. There'll be
only one entry in the xarray and all the CPUs in the system will
be assumed identical.

The framework's SMT control provides two interface to the users [1]
through /sys/devices/system/cpu/smt/control
(Documentation/ABI/testing/sysfs-devices-system-cpu):

1) enable SMT by writing "on" and disable by "off"
2) enable SMT by writing max_thread_number or disable by writing 1

Both method support to completely disable/enable the SMT cores so both
work correctly for symmetric SMT platform and asymmetric platform with
non-SMT and one type SMT cores like:

core A: 1 thread
core B: X (X!=1) threads

Note that for a theoretically possible multiple SMT-X (X>1) core
platform the SMT control is also supported as expected but only
by writing the "on/off" method.

Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Hanjun Guo <guohanjun@huawei.com>
Reviewed-by: Pierre Gondois <pierre.gondois@arm.com>
Reviewed-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
Reviewed-by: Sudeep Holla <sudeep.holla@arm.com>
Link: https://lore.kernel.org/r/20250311075143.61078-4-yangyicong@huawei.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
arch/arm64/kernel/topology.c

index cb180684d10d5b5be90602878ce75f44da90d696..0bcea4f89ea821c3bbf87c6d985570dfcc07c30b 100644 (file)
 #include <linux/arch_topology.h>
 #include <linux/cacheinfo.h>
 #include <linux/cpufreq.h>
+#include <linux/cpu_smt.h>
 #include <linux/init.h>
 #include <linux/percpu.h>
+#include <linux/xarray.h>
 
 #include <asm/cpu.h>
 #include <asm/cputype.h>
@@ -37,17 +39,28 @@ static bool __init acpi_cpu_is_threaded(int cpu)
        return !!is_threaded;
 }
 
+struct cpu_smt_info {
+       unsigned int thread_num;
+       int core_id;
+};
+
 /*
  * Propagate the topology information of the processor_topology_node tree to the
  * cpu_topology array.
  */
 int __init parse_acpi_topology(void)
 {
+       unsigned int max_smt_thread_num = 1;
+       struct cpu_smt_info *entry;
+       struct xarray hetero_cpu;
+       unsigned long hetero_id;
        int cpu, topology_id;
 
        if (acpi_disabled)
                return 0;
 
+       xa_init(&hetero_cpu);
+
        for_each_possible_cpu(cpu) {
                topology_id = find_acpi_cpu_topology(cpu, 0);
                if (topology_id < 0)
@@ -57,6 +70,34 @@ int __init parse_acpi_topology(void)
                        cpu_topology[cpu].thread_id = topology_id;
                        topology_id = find_acpi_cpu_topology(cpu, 1);
                        cpu_topology[cpu].core_id   = topology_id;
+
+                       /*
+                        * In the PPTT, CPUs below a node with the 'identical
+                        * implementation' flag have the same number of threads.
+                        * Count the number of threads for only one CPU (i.e.
+                        * one core_id) among those with the same hetero_id.
+                        * See the comment of find_acpi_cpu_topology_hetero_id()
+                        * for more details.
+                        *
+                        * One entry is created for each node having:
+                        * - the 'identical implementation' flag
+                        * - its parent not having the flag
+                        */
+                       hetero_id = find_acpi_cpu_topology_hetero_id(cpu);
+                       entry = xa_load(&hetero_cpu, hetero_id);
+                       if (!entry) {
+                               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+                               WARN_ON_ONCE(!entry);
+
+                               if (entry) {
+                                       entry->core_id = topology_id;
+                                       entry->thread_num = 1;
+                                       xa_store(&hetero_cpu, hetero_id,
+                                                entry, GFP_KERNEL);
+                               }
+                       } else if (entry->core_id == topology_id) {
+                               entry->thread_num++;
+                       }
                } else {
                        cpu_topology[cpu].thread_id  = -1;
                        cpu_topology[cpu].core_id    = topology_id;
@@ -67,6 +108,19 @@ int __init parse_acpi_topology(void)
                cpu_topology[cpu].package_id = topology_id;
        }
 
+       /*
+        * This is a short loop since the number of XArray elements is the
+        * number of heterogeneous CPU clusters. On a homogeneous system
+        * there's only one entry in the XArray.
+        */
+       xa_for_each(&hetero_cpu, hetero_id, entry) {
+               max_smt_thread_num = max(max_smt_thread_num, entry->thread_num);
+               xa_erase(&hetero_cpu, hetero_id);
+               kfree(entry);
+       }
+
+       cpu_smt_set_num_threads(max_smt_thread_num, max_smt_thread_num);
+       xa_destroy(&hetero_cpu);
        return 0;
 }
 #endif