Skip to content

Commit 8ae9e2d

Browse files
committed
Merge branch 'for-next/smt-control' into for-next/core
* for-next/smt-control: : Support SMT control on arm64 arm64: Kconfig: Enable HOTPLUG_SMT arm64: topology: Support SMT control on ACPI based system arch_topology: Support SMT control for OF based system cpu/SMT: Provide a default topology_is_primary_thread()
2 parents 8cc14fd + eed4583 commit 8ae9e2d

File tree

6 files changed

+98
-1
lines changed

6 files changed

+98
-1
lines changed

arch/arm64/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ config ARM64
250250
select HAVE_KRETPROBES
251251
select HAVE_GENERIC_VDSO
252252
select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU
253+
select HOTPLUG_SMT if HOTPLUG_CPU
253254
select IRQ_DOMAIN
254255
select IRQ_FORCED_THREADING
255256
select KASAN_VMALLOC if KASAN

arch/arm64/kernel/topology.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
#include <linux/arch_topology.h>
1616
#include <linux/cacheinfo.h>
1717
#include <linux/cpufreq.h>
18+
#include <linux/cpu_smt.h>
1819
#include <linux/init.h>
1920
#include <linux/percpu.h>
2021
#include <linux/sched/isolation.h>
22+
#include <linux/xarray.h>
2123

2224
#include <asm/cpu.h>
2325
#include <asm/cputype.h>
@@ -38,17 +40,28 @@ static bool __init acpi_cpu_is_threaded(int cpu)
3840
return !!is_threaded;
3941
}
4042

43+
struct cpu_smt_info {
44+
unsigned int thread_num;
45+
int core_id;
46+
};
47+
4148
/*
4249
* Propagate the topology information of the processor_topology_node tree to the
4350
* cpu_topology array.
4451
*/
4552
int __init parse_acpi_topology(void)
4653
{
54+
unsigned int max_smt_thread_num = 1;
55+
struct cpu_smt_info *entry;
56+
struct xarray hetero_cpu;
57+
unsigned long hetero_id;
4758
int cpu, topology_id;
4859

4960
if (acpi_disabled)
5061
return 0;
5162

63+
xa_init(&hetero_cpu);
64+
5265
for_each_possible_cpu(cpu) {
5366
topology_id = find_acpi_cpu_topology(cpu, 0);
5467
if (topology_id < 0)
@@ -58,6 +71,34 @@ int __init parse_acpi_topology(void)
5871
cpu_topology[cpu].thread_id = topology_id;
5972
topology_id = find_acpi_cpu_topology(cpu, 1);
6073
cpu_topology[cpu].core_id = topology_id;
74+
75+
/*
76+
* In the PPTT, CPUs below a node with the 'identical
77+
* implementation' flag have the same number of threads.
78+
* Count the number of threads for only one CPU (i.e.
79+
* one core_id) among those with the same hetero_id.
80+
* See the comment of find_acpi_cpu_topology_hetero_id()
81+
* for more details.
82+
*
83+
* One entry is created for each node having:
84+
* - the 'identical implementation' flag
85+
* - its parent not having the flag
86+
*/
87+
hetero_id = find_acpi_cpu_topology_hetero_id(cpu);
88+
entry = xa_load(&hetero_cpu, hetero_id);
89+
if (!entry) {
90+
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
91+
WARN_ON_ONCE(!entry);
92+
93+
if (entry) {
94+
entry->core_id = topology_id;
95+
entry->thread_num = 1;
96+
xa_store(&hetero_cpu, hetero_id,
97+
entry, GFP_KERNEL);
98+
}
99+
} else if (entry->core_id == topology_id) {
100+
entry->thread_num++;
101+
}
61102
} else {
62103
cpu_topology[cpu].thread_id = -1;
63104
cpu_topology[cpu].core_id = topology_id;
@@ -68,6 +109,19 @@ int __init parse_acpi_topology(void)
68109
cpu_topology[cpu].package_id = topology_id;
69110
}
70111

112+
/*
113+
* This is a short loop since the number of XArray elements is the
114+
* number of heterogeneous CPU clusters. On a homogeneous system
115+
* there's only one entry in the XArray.
116+
*/
117+
xa_for_each(&hetero_cpu, hetero_id, entry) {
118+
max_smt_thread_num = max(max_smt_thread_num, entry->thread_num);
119+
xa_erase(&hetero_cpu, hetero_id);
120+
kfree(entry);
121+
}
122+
123+
cpu_smt_set_num_threads(max_smt_thread_num, max_smt_thread_num);
124+
xa_destroy(&hetero_cpu);
71125
return 0;
72126
}
73127
#endif

arch/powerpc/include/asm/topology.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ static inline bool topology_is_primary_thread(unsigned int cpu)
152152
{
153153
return cpu == cpu_first_thread_sibling(cpu);
154154
}
155+
#define topology_is_primary_thread topology_is_primary_thread
155156

156157
static inline bool topology_smt_thread_allowed(unsigned int cpu)
157158
{

arch/x86/include/asm/topology.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,11 @@ static inline bool topology_is_primary_thread(unsigned int cpu)
229229
{
230230
return cpumask_test_cpu(cpu, cpu_primary_thread_mask);
231231
}
232+
#define topology_is_primary_thread topology_is_primary_thread
232233

233234
#else /* CONFIG_SMP */
234235
static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; }
235236
static inline int topology_max_smt_threads(void) { return 1; }
236-
static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }
237237
static inline unsigned int topology_amd_nodes_per_pkg(void) { return 1; }
238238
#endif /* !CONFIG_SMP */
239239

drivers/base/arch_topology.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/cleanup.h>
1212
#include <linux/cpu.h>
1313
#include <linux/cpufreq.h>
14+
#include <linux/cpu_smt.h>
1415
#include <linux/device.h>
1516
#include <linux/of.h>
1617
#include <linux/slab.h>
@@ -508,6 +509,10 @@ core_initcall(free_raw_capacity);
508509
#endif
509510

510511
#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
512+
513+
/* Used to enable the SMT control */
514+
static unsigned int max_smt_thread_num = 1;
515+
511516
/*
512517
* This function returns the logic cpu number of the node.
513518
* There are basically three kinds of return values:
@@ -567,6 +572,8 @@ static int __init parse_core(struct device_node *core, int package_id,
567572
i++;
568573
} while (1);
569574

575+
max_smt_thread_num = max_t(unsigned int, max_smt_thread_num, i);
576+
570577
cpu = get_cpu_for_node(core);
571578
if (cpu >= 0) {
572579
if (!leaf) {
@@ -679,6 +686,17 @@ static int __init parse_socket(struct device_node *socket)
679686
if (!has_socket)
680687
ret = parse_cluster(socket, 0, -1, 0);
681688

689+
/*
690+
* Reset the max_smt_thread_num to 1 on failure. Since on failure
691+
* we need to notify the framework the SMT is not supported, but
692+
* max_smt_thread_num can be initialized to the SMT thread number
693+
* of the cores which are successfully parsed.
694+
*/
695+
if (ret)
696+
max_smt_thread_num = 1;
697+
698+
cpu_smt_set_num_threads(max_smt_thread_num, max_smt_thread_num);
699+
682700
return ret;
683701
}
684702

include/linux/topology.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,29 @@ static inline const struct cpumask *cpu_smt_mask(int cpu)
240240
}
241241
#endif
242242

243+
#ifndef topology_is_primary_thread
244+
245+
static inline bool topology_is_primary_thread(unsigned int cpu)
246+
{
247+
/*
248+
* When disabling SMT, the primary thread of the SMT will remain
249+
* enabled/active. Architectures that have a special primary thread
250+
* (e.g. x86) need to override this function. Otherwise the first
251+
* thread in the SMT can be made the primary thread.
252+
*
253+
* The sibling cpumask of an offline CPU always contains the CPU
254+
* itself on architectures using the implementation of
255+
* CONFIG_GENERIC_ARCH_TOPOLOGY for building their topology.
256+
* Other architectures not using CONFIG_GENERIC_ARCH_TOPOLOGY for
257+
* building their topology have to check whether to use this default
258+
* implementation or to override it.
259+
*/
260+
return cpu == cpumask_first(topology_sibling_cpumask(cpu));
261+
}
262+
#define topology_is_primary_thread topology_is_primary_thread
263+
264+
#endif
265+
243266
static inline const struct cpumask *cpu_cpu_mask(int cpu)
244267
{
245268
return cpumask_of_node(cpu_to_node(cpu));

0 commit comments

Comments
 (0)