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:
commit
d82e6762b0
|
@ -555,6 +555,7 @@ Description: Control Symmetric Multi Threading (SMT)
|
|||
================ =========================================
|
||||
"on" SMT is enabled
|
||||
"off" SMT is disabled
|
||||
"<N>" SMT is enabled with N threads per core.
|
||||
"forceoff" SMT is force disabled. Cannot be changed.
|
||||
"notsupported" SMT is not supported by the CPU
|
||||
"notimplemented" SMT runtime toggling is not
|
||||
|
|
|
@ -34,6 +34,9 @@ config ARCH_HAS_SUBPAGE_FAULTS
|
|||
config HOTPLUG_SMT
|
||||
bool
|
||||
|
||||
config SMT_NUM_THREADS_DYNAMIC
|
||||
bool
|
||||
|
||||
# Selected by HOTPLUG_CORE_SYNC_DEAD or HOTPLUG_CORE_SYNC_FULL
|
||||
config HOTPLUG_CORE_SYNC
|
||||
bool
|
||||
|
|
|
@ -136,10 +136,11 @@ static inline int topology_max_smt_threads(void)
|
|||
return __max_smt_threads;
|
||||
}
|
||||
|
||||
#include <linux/cpu_smt.h>
|
||||
|
||||
int topology_update_package_map(unsigned int apicid, unsigned int cpu);
|
||||
int topology_update_die_map(unsigned int dieid, unsigned int cpu);
|
||||
int topology_phys_to_logical_pkg(unsigned int pkg);
|
||||
bool topology_smt_supported(void);
|
||||
|
||||
extern 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_smt_threads(void) { return 1; }
|
||||
static inline bool topology_is_primary_thread(unsigned int cpu) { return true; }
|
||||
static inline bool topology_smt_supported(void) { return false; }
|
||||
#endif /* !CONFIG_SMP */
|
||||
|
||||
static inline void arch_fix_phys_package_id(int num, u32 slot)
|
||||
|
|
|
@ -2317,7 +2317,7 @@ void __init arch_cpu_finalize_init(void)
|
|||
* identify_boot_cpu() initialized SMT support information, let the
|
||||
* core code know.
|
||||
*/
|
||||
cpu_smt_check_topology();
|
||||
cpu_smt_set_num_threads(smp_num_siblings, smp_num_siblings);
|
||||
|
||||
if (!IS_ENABLED(CONFIG_SMP)) {
|
||||
pr_info("CPU: ");
|
||||
|
|
|
@ -326,14 +326,6 @@ static void notrace start_secondary(void *unused)
|
|||
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
|
||||
* @phys_pkg: The physical package id to map
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/compiler.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
#include <linux/cpu_smt.h>
|
||||
|
||||
struct device;
|
||||
struct device_node;
|
||||
|
@ -204,30 +205,6 @@ void cpuhp_report_idle_dead(void);
|
|||
static inline void cpuhp_report_idle_dead(void) { }
|
||||
#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_auto_nosmt(void);
|
||||
|
||||
|
|
|
@ -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_ */
|
142
kernel/cpu.c
142
kernel/cpu.c
|
@ -592,7 +592,10 @@ static void lockdep_release_cpus_lock(void)
|
|||
void __weak arch_smt_update(void) { }
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_SMT
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -606,16 +609,33 @@ void __init cpu_smt_disable(bool force)
|
|||
pr_info("SMT: disabled\n");
|
||||
cpu_smt_control = CPU_SMT_DISABLED;
|
||||
}
|
||||
cpu_smt_num_threads = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The decision whether SMT is supported can only be done after the full
|
||||
* 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_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)
|
||||
|
@ -625,9 +645,23 @@ static int __init smt_cmdline_disable(char *str)
|
|||
}
|
||||
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)
|
||||
{
|
||||
if (cpu_smt_control == CPU_SMT_ENABLED)
|
||||
if (cpu_smt_control == CPU_SMT_ENABLED && cpu_smt_thread_allowed(cpu))
|
||||
return true;
|
||||
|
||||
if (topology_is_primary_thread(cpu))
|
||||
|
@ -650,22 +684,8 @@ bool cpu_smt_possible(void)
|
|||
}
|
||||
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
|
||||
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
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
* 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) {
|
||||
if (topology_is_primary_thread(cpu))
|
||||
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);
|
||||
if (ret)
|
||||
break;
|
||||
|
@ -2660,6 +2696,8 @@ int cpuhp_smt_enable(void)
|
|||
/* Skip online CPUs and CPUs on offline nodes */
|
||||
if (cpu_online(cpu) || !node_online(cpu_to_node(cpu)))
|
||||
continue;
|
||||
if (!cpu_smt_thread_allowed(cpu))
|
||||
continue;
|
||||
ret = _cpu_up(cpu, 0, CPUHP_ONLINE);
|
||||
if (ret)
|
||||
break;
|
||||
|
@ -2838,20 +2876,19 @@ static const struct attribute_group cpuhp_cpu_root_attr_group = {
|
|||
|
||||
#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
|
||||
__store_smt_control(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int ctrlval, ret;
|
||||
|
||||
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;
|
||||
int ctrlval, ret, num_threads, orig_threads;
|
||||
bool force_off;
|
||||
|
||||
if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
|
||||
return -EPERM;
|
||||
|
@ -2859,21 +2896,39 @@ __store_smt_control(struct device *dev, struct device_attribute *attr,
|
|||
if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
|
||||
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();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ctrlval != cpu_smt_control) {
|
||||
switch (ctrlval) {
|
||||
case CPU_SMT_ENABLED:
|
||||
ret = cpuhp_smt_enable();
|
||||
break;
|
||||
case CPU_SMT_DISABLED:
|
||||
case CPU_SMT_FORCE_DISABLED:
|
||||
ret = cpuhp_smt_disable(ctrlval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
orig_threads = cpu_smt_num_threads;
|
||||
cpu_smt_num_threads = num_threads;
|
||||
|
||||
force_off = ctrlval != cpu_smt_control && ctrlval == CPU_SMT_FORCE_DISABLED;
|
||||
|
||||
if (num_threads > orig_threads)
|
||||
ret = cpuhp_smt_enable();
|
||||
else if (num_threads < orig_threads || force_off)
|
||||
ret = cpuhp_smt_disable(ctrlval);
|
||||
|
||||
unlock_device_hotplug();
|
||||
return ret ? ret : count;
|
||||
|
@ -2901,6 +2956,17 @@ static ssize_t control_show(struct device *dev,
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue