SMP core changes for powerpc

-----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmTDdHMTHHRnbHhAbGlu
 dXRyb25peC5kZQAKCRCmGPVMDXSYoawDEACf7tZeCfwnkEVzBO45mKujBstQyV+v
 yATR7YRFG3Li9VaRP/rOrFxh+UPM2YbvQCgcT2BECl5gkBm7j/jgTiL47atN5VCo
 Sg9fDzjkf6+A1ac62kriQT0EyhYYN/V6DxByhqSLvxev9626ge93wBKmChohGOgj
 j66PEg5z+Luw9aTdyKm3cEuXGYyCmdWTgZ6z4f4VI+rVBXFUMiZl28eMlLH+eyVM
 +ntkDoNw00TqypSrcSr8WEzJc3SNAqUsLOW+Mogm4AJK8sKeFtdkjCLFDcV1dLmZ
 9Ak8OxeQGNhh538yCLYiNDu57xpQffS4E2t+Pusv8ZHc6ww5J8vsPq3p9323LbyF
 FXcREHM8W5cKLdy4hzqeqKx2YK4shquYXH10WIbVQXqbxMUD5wGCYuQTS12V+QW0
 1Ut48/RS3a6kaKvX475enFrR/wQNSTJkM+ajFSGY3eSNp9v9EmTepw3aY8RXw+Gr
 QRxCuM4MgaUazJ0RtbjbzSRK2r8MObj+aurfvMQZGFmkkw0DiUZNOnb5VPZSrqb+
 laNQKKAdG99NlTNyvLSSgYTX+FM0AbqKVWnIO4b+3wMvYxfiENKDWVzdQWksNz6U
 J5j7qDqZQ45kEow0Xn0lKxz1zKdcJLZPFjExrgYkRTaRp7VwcQ8st2Lbj1XVk7Wr
 wqXouAvhBSqWEA==
 =jF0X
 -----END PGP SIGNATURE-----

Merge tag 'smp-core-for-ppc-23-07-28' of https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip into topic/cpu-smt

SMP core changes for powerpc
This commit is contained in:
Michael Ellerman 2023-08-02 22:39:48 +10:00
commit d82e6762b0
8 changed files with 145 additions and 73 deletions

View File

@ -555,6 +555,7 @@ Description: Control Symmetric Multi Threading (SMT)
================ ========================================= ================ =========================================
"on" SMT is enabled "on" SMT is enabled
"off" SMT is disabled "off" SMT is disabled
"<N>" SMT is enabled with N threads per core.
"forceoff" SMT is force disabled. Cannot be changed. "forceoff" SMT is force disabled. Cannot be changed.
"notsupported" SMT is not supported by the CPU "notsupported" SMT is not supported by the CPU
"notimplemented" SMT runtime toggling is not "notimplemented" SMT runtime toggling is not

View File

@ -34,6 +34,9 @@ config ARCH_HAS_SUBPAGE_FAULTS
config HOTPLUG_SMT config HOTPLUG_SMT
bool bool
config SMT_NUM_THREADS_DYNAMIC
bool
# Selected by HOTPLUG_CORE_SYNC_DEAD or HOTPLUG_CORE_SYNC_FULL # Selected by HOTPLUG_CORE_SYNC_DEAD or HOTPLUG_CORE_SYNC_FULL
config HOTPLUG_CORE_SYNC config HOTPLUG_CORE_SYNC
bool bool

View File

@ -136,10 +136,11 @@ static inline int topology_max_smt_threads(void)
return __max_smt_threads; return __max_smt_threads;
} }
#include <linux/cpu_smt.h>
int topology_update_package_map(unsigned int apicid, unsigned int cpu); int topology_update_package_map(unsigned int apicid, unsigned int cpu);
int topology_update_die_map(unsigned int dieid, unsigned int cpu); int topology_update_die_map(unsigned int dieid, unsigned int cpu);
int topology_phys_to_logical_pkg(unsigned int pkg); int topology_phys_to_logical_pkg(unsigned int pkg);
bool topology_smt_supported(void);
extern struct cpumask __cpu_primary_thread_mask; extern struct cpumask __cpu_primary_thread_mask;
#define cpu_primary_thread_mask ((const struct cpumask *)&__cpu_primary_thread_mask) #define cpu_primary_thread_mask ((const struct cpumask *)&__cpu_primary_thread_mask)
@ -162,7 +163,6 @@ 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_die_per_package(void) { return 1; }
static inline int topology_max_smt_threads(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; } static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }
static inline bool topology_smt_supported(void) { return false; }
#endif /* !CONFIG_SMP */ #endif /* !CONFIG_SMP */
static inline void arch_fix_phys_package_id(int num, u32 slot) static inline void arch_fix_phys_package_id(int num, u32 slot)

View File

@ -2317,7 +2317,7 @@ void __init arch_cpu_finalize_init(void)
* identify_boot_cpu() initialized SMT support information, let the * identify_boot_cpu() initialized SMT support information, let the
* core code know. * core code know.
*/ */
cpu_smt_check_topology(); cpu_smt_set_num_threads(smp_num_siblings, smp_num_siblings);
if (!IS_ENABLED(CONFIG_SMP)) { if (!IS_ENABLED(CONFIG_SMP)) {
pr_info("CPU: "); pr_info("CPU: ");

View File

@ -326,14 +326,6 @@ static void notrace start_secondary(void *unused)
cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
} }
/**
* topology_smt_supported - Check whether SMT is supported by the CPUs
*/
bool topology_smt_supported(void)
{
return smp_num_siblings > 1;
}
/** /**
* topology_phys_to_logical_pkg - Map a physical package id to a logical * topology_phys_to_logical_pkg - Map a physical package id to a logical
* @phys_pkg: The physical package id to map * @phys_pkg: The physical package id to map

View File

@ -18,6 +18,7 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/cpuhotplug.h> #include <linux/cpuhotplug.h>
#include <linux/cpu_smt.h>
struct device; struct device;
struct device_node; struct device_node;
@ -204,30 +205,6 @@ void cpuhp_report_idle_dead(void);
static inline void cpuhp_report_idle_dead(void) { } static inline void cpuhp_report_idle_dead(void) { }
#endif /* #ifdef CONFIG_HOTPLUG_CPU */ #endif /* #ifdef CONFIG_HOTPLUG_CPU */
enum cpuhp_smt_control {
CPU_SMT_ENABLED,
CPU_SMT_DISABLED,
CPU_SMT_FORCE_DISABLED,
CPU_SMT_NOT_SUPPORTED,
CPU_SMT_NOT_IMPLEMENTED,
};
#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_SMT)
extern enum cpuhp_smt_control cpu_smt_control;
extern void cpu_smt_disable(bool force);
extern void cpu_smt_check_topology(void);
extern bool cpu_smt_possible(void);
extern int cpuhp_smt_enable(void);
extern int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval);
#else
# define cpu_smt_control (CPU_SMT_NOT_IMPLEMENTED)
static inline void cpu_smt_disable(bool force) { }
static inline void cpu_smt_check_topology(void) { }
static inline bool cpu_smt_possible(void) { return false; }
static inline int cpuhp_smt_enable(void) { return 0; }
static inline int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) { return 0; }
#endif
extern bool cpu_mitigations_off(void); extern bool cpu_mitigations_off(void);
extern bool cpu_mitigations_auto_nosmt(void); extern bool cpu_mitigations_auto_nosmt(void);

33
include/linux/cpu_smt.h Normal file
View File

@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_CPU_SMT_H_
#define _LINUX_CPU_SMT_H_
enum cpuhp_smt_control {
CPU_SMT_ENABLED,
CPU_SMT_DISABLED,
CPU_SMT_FORCE_DISABLED,
CPU_SMT_NOT_SUPPORTED,
CPU_SMT_NOT_IMPLEMENTED,
};
#if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_SMT)
extern enum cpuhp_smt_control cpu_smt_control;
extern unsigned int cpu_smt_num_threads;
extern void cpu_smt_disable(bool force);
extern void cpu_smt_set_num_threads(unsigned int num_threads,
unsigned int max_threads);
extern bool cpu_smt_possible(void);
extern int cpuhp_smt_enable(void);
extern int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval);
#else
# define cpu_smt_control (CPU_SMT_NOT_IMPLEMENTED)
# define cpu_smt_num_threads 1
static inline void cpu_smt_disable(bool force) { }
static inline void cpu_smt_set_num_threads(unsigned int num_threads,
unsigned int max_threads) { }
static inline bool cpu_smt_possible(void) { return false; }
static inline int cpuhp_smt_enable(void) { return 0; }
static inline int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval) { return 0; }
#endif
#endif /* _LINUX_CPU_SMT_H_ */

View File

@ -592,7 +592,10 @@ static void lockdep_release_cpus_lock(void)
void __weak arch_smt_update(void) { } void __weak arch_smt_update(void) { }
#ifdef CONFIG_HOTPLUG_SMT #ifdef CONFIG_HOTPLUG_SMT
enum cpuhp_smt_control cpu_smt_control __read_mostly = CPU_SMT_ENABLED; enum cpuhp_smt_control cpu_smt_control __read_mostly = CPU_SMT_ENABLED;
static unsigned int cpu_smt_max_threads __ro_after_init;
unsigned int cpu_smt_num_threads __read_mostly = UINT_MAX;
void __init cpu_smt_disable(bool force) void __init cpu_smt_disable(bool force)
{ {
@ -606,16 +609,33 @@ void __init cpu_smt_disable(bool force)
pr_info("SMT: disabled\n"); pr_info("SMT: disabled\n");
cpu_smt_control = CPU_SMT_DISABLED; cpu_smt_control = CPU_SMT_DISABLED;
} }
cpu_smt_num_threads = 1;
} }
/* /*
* The decision whether SMT is supported can only be done after the full * The decision whether SMT is supported can only be done after the full
* CPU identification. Called from architecture code. * CPU identification. Called from architecture code.
*/ */
void __init cpu_smt_check_topology(void) void __init cpu_smt_set_num_threads(unsigned int num_threads,
unsigned int max_threads)
{ {
if (!topology_smt_supported()) WARN_ON(!num_threads || (num_threads > max_threads));
if (max_threads == 1)
cpu_smt_control = CPU_SMT_NOT_SUPPORTED; cpu_smt_control = CPU_SMT_NOT_SUPPORTED;
cpu_smt_max_threads = max_threads;
/*
* If SMT has been disabled via the kernel command line or SMT is
* not supported, set cpu_smt_num_threads to 1 for consistency.
* If enabled, take the architecture requested number of threads
* to bring up into account.
*/
if (cpu_smt_control != CPU_SMT_ENABLED)
cpu_smt_num_threads = 1;
else if (num_threads < cpu_smt_num_threads)
cpu_smt_num_threads = num_threads;
} }
static int __init smt_cmdline_disable(char *str) static int __init smt_cmdline_disable(char *str)
@ -625,9 +645,23 @@ static int __init smt_cmdline_disable(char *str)
} }
early_param("nosmt", smt_cmdline_disable); early_param("nosmt", smt_cmdline_disable);
/*
* For Archicture supporting partial SMT states check if the thread is allowed.
* Otherwise this has already been checked through cpu_smt_max_threads when
* setting the SMT level.
*/
static inline bool cpu_smt_thread_allowed(unsigned int cpu)
{
#ifdef CONFIG_SMT_NUM_THREADS_DYNAMIC
return topology_smt_thread_allowed(cpu);
#else
return true;
#endif
}
static inline bool cpu_smt_allowed(unsigned int cpu) static inline bool cpu_smt_allowed(unsigned int cpu)
{ {
if (cpu_smt_control == CPU_SMT_ENABLED) if (cpu_smt_control == CPU_SMT_ENABLED && cpu_smt_thread_allowed(cpu))
return true; return true;
if (topology_is_primary_thread(cpu)) if (topology_is_primary_thread(cpu))
@ -650,22 +684,8 @@ bool cpu_smt_possible(void)
} }
EXPORT_SYMBOL_GPL(cpu_smt_possible); EXPORT_SYMBOL_GPL(cpu_smt_possible);
static inline bool cpuhp_smt_aware(void)
{
return topology_smt_supported();
}
static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
{
return cpu_primary_thread_mask;
}
#else #else
static inline bool cpu_smt_allowed(unsigned int cpu) { return true; } static inline bool cpu_smt_allowed(unsigned int cpu) { return true; }
static inline bool cpuhp_smt_aware(void) { return false; }
static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
{
return cpu_present_mask;
}
#endif #endif
static inline enum cpuhp_state static inline enum cpuhp_state
@ -1793,6 +1813,16 @@ static int __init parallel_bringup_parse_param(char *arg)
} }
early_param("cpuhp.parallel", parallel_bringup_parse_param); early_param("cpuhp.parallel", parallel_bringup_parse_param);
static inline bool cpuhp_smt_aware(void)
{
return cpu_smt_max_threads > 1;
}
static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
{
return cpu_primary_thread_mask;
}
/* /*
* On architectures which have enabled parallel bringup this invokes all BP * On architectures which have enabled parallel bringup this invokes all BP
* prepare states for each of the to be onlined APs first. The last state * prepare states for each of the to be onlined APs first. The last state
@ -2626,6 +2656,12 @@ int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval)
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
if (topology_is_primary_thread(cpu)) if (topology_is_primary_thread(cpu))
continue; continue;
/*
* Disable can be called with CPU_SMT_ENABLED when changing
* from a higher to lower number of SMT threads per core.
*/
if (ctrlval == CPU_SMT_ENABLED && cpu_smt_thread_allowed(cpu))
continue;
ret = cpu_down_maps_locked(cpu, CPUHP_OFFLINE); ret = cpu_down_maps_locked(cpu, CPUHP_OFFLINE);
if (ret) if (ret)
break; break;
@ -2660,6 +2696,8 @@ int cpuhp_smt_enable(void)
/* Skip online CPUs and CPUs on offline nodes */ /* Skip online CPUs and CPUs on offline nodes */
if (cpu_online(cpu) || !node_online(cpu_to_node(cpu))) if (cpu_online(cpu) || !node_online(cpu_to_node(cpu)))
continue; continue;
if (!cpu_smt_thread_allowed(cpu))
continue;
ret = _cpu_up(cpu, 0, CPUHP_ONLINE); ret = _cpu_up(cpu, 0, CPUHP_ONLINE);
if (ret) if (ret)
break; break;
@ -2838,20 +2876,19 @@ static const struct attribute_group cpuhp_cpu_root_attr_group = {
#ifdef CONFIG_HOTPLUG_SMT #ifdef CONFIG_HOTPLUG_SMT
static bool cpu_smt_num_threads_valid(unsigned int threads)
{
if (IS_ENABLED(CONFIG_SMT_NUM_THREADS_DYNAMIC))
return threads >= 1 && threads <= cpu_smt_max_threads;
return threads == 1 || threads == cpu_smt_max_threads;
}
static ssize_t static ssize_t
__store_smt_control(struct device *dev, struct device_attribute *attr, __store_smt_control(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
int ctrlval, ret; int ctrlval, ret, num_threads, orig_threads;
bool force_off;
if (sysfs_streq(buf, "on"))
ctrlval = CPU_SMT_ENABLED;
else if (sysfs_streq(buf, "off"))
ctrlval = CPU_SMT_DISABLED;
else if (sysfs_streq(buf, "forceoff"))
ctrlval = CPU_SMT_FORCE_DISABLED;
else
return -EINVAL;
if (cpu_smt_control == CPU_SMT_FORCE_DISABLED) if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
return -EPERM; return -EPERM;
@ -2859,21 +2896,39 @@ __store_smt_control(struct device *dev, struct device_attribute *attr,
if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED) if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
return -ENODEV; return -ENODEV;
if (sysfs_streq(buf, "on")) {
ctrlval = CPU_SMT_ENABLED;
num_threads = cpu_smt_max_threads;
} else if (sysfs_streq(buf, "off")) {
ctrlval = CPU_SMT_DISABLED;
num_threads = 1;
} else if (sysfs_streq(buf, "forceoff")) {
ctrlval = CPU_SMT_FORCE_DISABLED;
num_threads = 1;
} else if (kstrtoint(buf, 10, &num_threads) == 0) {
if (num_threads == 1)
ctrlval = CPU_SMT_DISABLED;
else if (cpu_smt_num_threads_valid(num_threads))
ctrlval = CPU_SMT_ENABLED;
else
return -EINVAL;
} else {
return -EINVAL;
}
ret = lock_device_hotplug_sysfs(); ret = lock_device_hotplug_sysfs();
if (ret) if (ret)
return ret; return ret;
if (ctrlval != cpu_smt_control) { orig_threads = cpu_smt_num_threads;
switch (ctrlval) { cpu_smt_num_threads = num_threads;
case CPU_SMT_ENABLED:
ret = cpuhp_smt_enable(); force_off = ctrlval != cpu_smt_control && ctrlval == CPU_SMT_FORCE_DISABLED;
break;
case CPU_SMT_DISABLED: if (num_threads > orig_threads)
case CPU_SMT_FORCE_DISABLED: ret = cpuhp_smt_enable();
ret = cpuhp_smt_disable(ctrlval); else if (num_threads < orig_threads || force_off)
break; ret = cpuhp_smt_disable(ctrlval);
}
}
unlock_device_hotplug(); unlock_device_hotplug();
return ret ? ret : count; return ret ? ret : count;
@ -2901,6 +2956,17 @@ static ssize_t control_show(struct device *dev,
{ {
const char *state = smt_states[cpu_smt_control]; const char *state = smt_states[cpu_smt_control];
#ifdef CONFIG_HOTPLUG_SMT
/*
* If SMT is enabled but not all threads are enabled then show the
* number of threads. If all threads are enabled show "on". Otherwise
* show the state name.
*/
if (cpu_smt_control == CPU_SMT_ENABLED &&
cpu_smt_num_threads != cpu_smt_max_threads)
return sysfs_emit(buf, "%d\n", cpu_smt_num_threads);
#endif
return snprintf(buf, PAGE_SIZE - 2, "%s\n", state); return snprintf(buf, PAGE_SIZE - 2, "%s\n", state);
} }