diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 9da9d58f1c024086f5b26c02526d0404585f4a51..a4456cd7f0f88c4ff66a7badc7bfed173b01f47f 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -242,7 +242,7 @@ config ARM64 select HAVE_KRETPROBES select HAVE_GENERIC_VDSO select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU - select HOTPLUG_SMT if (SMP && HOTPLUG_CPU) + select HOTPLUG_SMT if HOTPLUG_CPU select IRQ_DOMAIN select IRQ_FORCED_THREADING select KASAN_VMALLOC if KASAN diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index 3205dc763d995ce75f8aeef39640fb371466c4a7..94dd817d6536771e8681279820ba47c03809114b 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -774,7 +774,6 @@ CONFIG_CPU_MITIGATIONS=y # # General architecture-dependent options # -CONFIG_HOTPLUG_SMT=y CONFIG_HOTPLUG_CORE_SYNC=y CONFIG_HOTPLUG_CORE_SYNC_DEAD=y CONFIG_KPROBES=y diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 0dc360c32ec82d68d68c6b741588fb9089b43ac9..3b9ea46afb5285cb51a2847b54ce2ed4a4df9236 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -38,21 +39,27 @@ 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) { - int thread_num, max_smt_thread_num = 1; - struct xarray core_threads; + unsigned int max_smt_thread_num = 1; + struct cpu_smt_info *entry; + struct xarray hetero_cpu; + unsigned long hetero_id; int cpu, topology_id; - void *entry; if (acpi_disabled) return 0; - xa_init(&core_threads); + xa_init(&hetero_cpu); for_each_possible_cpu(cpu) { topology_id = find_acpi_cpu_topology(cpu, 0); @@ -64,18 +71,32 @@ int __init parse_acpi_topology(void) topology_id = find_acpi_cpu_topology(cpu, 1); cpu_topology[cpu].core_id = topology_id; - entry = xa_load(&core_threads, 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) { - xa_store(&core_threads, topology_id, - xa_mk_value(1), GFP_KERNEL); - } else { - thread_num = xa_to_value(entry); - thread_num++; - xa_store(&core_threads, topology_id, - xa_mk_value(thread_num), GFP_KERNEL); - - if (thread_num > max_smt_thread_num) - max_smt_thread_num = thread_num; + 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; @@ -87,9 +108,19 @@ int __init parse_acpi_topology(void) cpu_topology[cpu].package_id = topology_id; } - topology_smt_set_num_threads(max_smt_thread_num); + /* + * 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); + } - xa_destroy(&core_threads); + cpu_smt_set_num_threads(max_smt_thread_num, max_smt_thread_num); + xa_destroy(&hetero_cpu); return 0; } #endif diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h index 16bacfe8c7a2ca1f97d403d2889e7135effbd978..da15b5efe8071a70676349c14d1f2ff68381e6f2 100644 --- a/arch/powerpc/include/asm/topology.h +++ b/arch/powerpc/include/asm/topology.h @@ -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) { diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h index 3235ba1e5b06d77f4f40962ef44888e62d30988c..61f6350b4ed1d29365eb72d2b4fe15b2a5bfdb82 100644 --- a/arch/x86/include/asm/topology.h +++ b/arch/x86/include/asm/topology.h @@ -153,6 +153,8 @@ 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 */ #define topology_max_packages() (1) static inline int @@ -162,7 +164,6 @@ topology_update_die_map(unsigned int dieid, unsigned int cpu) { return 0; } static inline int topology_phys_to_logical_pkg(unsigned int pkg) { return 0; } static inline int topology_max_die_per_package(void) { return 1; } static inline int topology_max_smt_threads(void) { return 1; } -static inline bool topology_is_primary_thread(unsigned int cpu) { return true; } #endif /* !CONFIG_SMP */ static inline void arch_fix_phys_package_id(int num, u32 slot) diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c index 6c058cd64a8d0d31e606822e5d822e3c47445919..1525d3e2f9d50d17f895c1845dbb9cc2d62e19cc 100644 --- a/drivers/base/arch_topology.c +++ b/drivers/base/arch_topology.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -485,6 +486,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: @@ -546,12 +551,7 @@ static int __init parse_core(struct device_node *core, int package_id, i++; } while (1); - /* - * We've already gotten threads number in this core, update the SMT - * threads number when necessary. - */ - if (i > topology_smt_get_num_threads()) - topology_smt_set_num_threads(i); + max_smt_thread_num = max_t(unsigned int, max_smt_thread_num, i); cpu = get_cpu_for_node(core); if (cpu >= 0) { @@ -665,6 +665,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; } @@ -758,36 +769,6 @@ const struct cpumask *cpu_clustergroup_mask(int cpu) return &cpu_topology[cpu].cluster_sibling; } -#ifdef CONFIG_HOTPLUG_SMT - -/* Maximum threads number per-Core */ -static unsigned int topology_smt_num_threads = 1; - -void __init topology_smt_set_num_threads(unsigned int num_threads) -{ - topology_smt_num_threads = num_threads; -} - -unsigned int __init topology_smt_get_num_threads(void) -{ - return topology_smt_num_threads; -} - -/* - * On SMT Hotplug the primary thread of the SMT won't be disabled. For x86 they - * seem to have a primary thread for special purpose. For other arthitectures - * like arm64 there's no such restriction for a primary thread, so make the - * first thread in the SMT as the primary thread. - */ -bool topology_is_primary_thread(unsigned int cpu) -{ - if (cpu == cpumask_first(topology_sibling_cpumask(cpu))) - return true; - - return false; -} -#endif - void update_siblings_masks(unsigned int cpuid) { struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; @@ -900,14 +881,6 @@ void __init init_cpu_topology(void) reset_cpu_topology(); } - /* - * By this stage we get to know whether we support SMT or not, update - * the information for the core. We don't support - * CONFIG_SMT_NUM_THREADS_DYNAMIC so make the max_threads == num_threads. - */ - cpu_smt_set_num_threads(topology_smt_get_num_threads(), - topology_smt_get_num_threads()); - for_each_possible_cpu(cpu) { ret = fetch_cache_info(cpu); if (!ret) diff --git a/include/linux/arch_topology.h b/include/linux/arch_topology.h index 0367f3a61838a1104fac125fabc01ec9d59a745b..a07b510e7dc55960e83dca5542f9e937925c66d9 100644 --- a/include/linux/arch_topology.h +++ b/include/linux/arch_topology.h @@ -92,20 +92,6 @@ void update_siblings_masks(unsigned int cpu); void remove_cpu_topology(unsigned int cpuid); void reset_cpu_topology(void); int parse_acpi_topology(void); - -#ifdef CONFIG_HOTPLUG_SMT -bool topology_is_primary_thread(unsigned int cpu); -void topology_smt_set_num_threads(unsigned int num_threads); -unsigned int topology_smt_get_num_threads(void); -#else -static inline bool topology_is_primary_thread(unsigned int cpu) { return false; } -static inline void topology_smt_set_num_threads(unsigned int num_threads) { } -static inline unsigned int topology_smt_get_num_threads(void) -{ - return 1; -} -#endif - #endif #endif /* _LINUX_ARCH_TOPOLOGY_H_ */ diff --git a/include/linux/topology.h b/include/linux/topology.h index a2f15fd0e527ecee030e0d1ed46011f1b06a83f5..44465c56cbc159cec4a873c50b0161aac6736bd9 100644 --- a/include/linux/topology.h +++ b/include/linux/topology.h @@ -241,6 +241,30 @@ static inline const struct cpumask *cpu_smt_mask(int cpu) } #endif +#ifndef topology_is_primary_thread + +#define topology_is_primary_thread 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 do have a special primary thread + * (e.g. x86) needs to override this function. Otherwise can make + * the first thread in the SMT as the primary thread. + * + * The sibling cpumask of an offline CPU contains always the CPU + * itself for 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)); +} + +#endif + static inline const struct cpumask *cpu_cpu_mask(int cpu) { return cpumask_of_node(cpu_to_node(cpu));