mirror of
https://github.com/torvalds/linux.git
synced 2026-05-29 17:43:52 +02:00
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()
This commit is contained in:
commit
8ae9e2d832
|
|
@ -250,6 +250,7 @@ config ARM64
|
|||
select HAVE_KRETPROBES
|
||||
select HAVE_GENERIC_VDSO
|
||||
select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU
|
||||
select HOTPLUG_SMT if HOTPLUG_CPU
|
||||
select IRQ_DOMAIN
|
||||
select IRQ_FORCED_THREADING
|
||||
select KASAN_VMALLOC if KASAN
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@
|
|||
#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/sched/isolation.h>
|
||||
#include <linux/xarray.h>
|
||||
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/cputype.h>
|
||||
|
|
@ -38,17 +40,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)
|
||||
|
|
@ -58,6 +71,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;
|
||||
|
|
@ -68,6 +109,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
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ static inline bool topology_is_primary_thread(unsigned int cpu)
|
|||
{
|
||||
return cpu == cpu_first_thread_sibling(cpu);
|
||||
}
|
||||
#define topology_is_primary_thread topology_is_primary_thread
|
||||
|
||||
static inline bool topology_smt_thread_allowed(unsigned int cpu)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -229,11 +229,11 @@ static inline bool topology_is_primary_thread(unsigned int cpu)
|
|||
{
|
||||
return cpumask_test_cpu(cpu, cpu_primary_thread_mask);
|
||||
}
|
||||
#define topology_is_primary_thread topology_is_primary_thread
|
||||
|
||||
#else /* CONFIG_SMP */
|
||||
static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; }
|
||||
static inline int topology_max_smt_threads(void) { return 1; }
|
||||
static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }
|
||||
static inline unsigned int topology_amd_nodes_per_pkg(void) { return 1; }
|
||||
#endif /* !CONFIG_SMP */
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/cleanup.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/cpu_smt.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -508,6 +509,10 @@ core_initcall(free_raw_capacity);
|
|||
#endif
|
||||
|
||||
#if defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
|
||||
|
||||
/* Used to enable the SMT control */
|
||||
static unsigned int max_smt_thread_num = 1;
|
||||
|
||||
/*
|
||||
* This function returns the logic cpu number of the node.
|
||||
* There are basically three kinds of return values:
|
||||
|
|
@ -567,6 +572,8 @@ static int __init parse_core(struct device_node *core, int package_id,
|
|||
i++;
|
||||
} while (1);
|
||||
|
||||
max_smt_thread_num = max_t(unsigned int, max_smt_thread_num, i);
|
||||
|
||||
cpu = get_cpu_for_node(core);
|
||||
if (cpu >= 0) {
|
||||
if (!leaf) {
|
||||
|
|
@ -679,6 +686,17 @@ static int __init parse_socket(struct device_node *socket)
|
|||
if (!has_socket)
|
||||
ret = parse_cluster(socket, 0, -1, 0);
|
||||
|
||||
/*
|
||||
* Reset the max_smt_thread_num to 1 on failure. Since on failure
|
||||
* we need to notify the framework the SMT is not supported, but
|
||||
* max_smt_thread_num can be initialized to the SMT thread number
|
||||
* of the cores which are successfully parsed.
|
||||
*/
|
||||
if (ret)
|
||||
max_smt_thread_num = 1;
|
||||
|
||||
cpu_smt_set_num_threads(max_smt_thread_num, max_smt_thread_num);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -240,6 +240,29 @@ static inline const struct cpumask *cpu_smt_mask(int cpu)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifndef topology_is_primary_thread
|
||||
|
||||
static inline bool topology_is_primary_thread(unsigned int cpu)
|
||||
{
|
||||
/*
|
||||
* When disabling SMT, the primary thread of the SMT will remain
|
||||
* enabled/active. Architectures that have a special primary thread
|
||||
* (e.g. x86) need to override this function. Otherwise the first
|
||||
* thread in the SMT can be made the primary thread.
|
||||
*
|
||||
* The sibling cpumask of an offline CPU always contains the CPU
|
||||
* itself on architectures using the implementation of
|
||||
* CONFIG_GENERIC_ARCH_TOPOLOGY for building their topology.
|
||||
* Other architectures not using CONFIG_GENERIC_ARCH_TOPOLOGY for
|
||||
* building their topology have to check whether to use this default
|
||||
* implementation or to override it.
|
||||
*/
|
||||
return cpu == cpumask_first(topology_sibling_cpumask(cpu));
|
||||
}
|
||||
#define topology_is_primary_thread topology_is_primary_thread
|
||||
|
||||
#endif
|
||||
|
||||
static inline const struct cpumask *cpu_cpu_mask(int cpu)
|
||||
{
|
||||
return cpumask_of_node(cpu_to_node(cpu));
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user