2023-07-05 14:57:41

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 00/10] Introduce SMT level and add PowerPC support

I'm taking over the series Michael sent previously [1] which is smartly
reviewing the initial series I sent [2]. This series is addressing the
comments sent by Thomas and me on the Michael's one.

Here is a short introduction to the issue this series is addressing:

When a new CPU is added, the kernel is activating all its threads. This
leads to weird, but functional, result when adding CPU on a SMT 4 system
for instance.

Here the newly added CPU 1 has 8 threads while the other one has 4 threads
active (system has been booted with the 'smt-enabled=4' kernel option):

ltcden3-lp12:~ # ppc64_cpu --info
Core 0: 0* 1* 2* 3* 4 5 6 7
Core 1: 8* 9* 10* 11* 12* 13* 14* 15*

This mixed SMT level may confused end users and/or some applications.

There is no SMT level recorded in the kernel (common code), neither in user
space, as far as I know. Such a level is helpful when adding new CPU or
when optimizing the energy efficiency (when reactivating CPUs).

When SMP and HOTPLUG_SMT are defined, this series is adding a new SMT level
(cpu_smt_num_threads) and few callbacks allowing the architecture code to
fine control this value, setting a max and a "at boot" level, and
controling whether a thread should be onlined or not.

v4:
Rebase on top of 6.5's updates
Remove a dependancy against the X86's symbol cpu_primary_thread_mask
v3:
Fix a build error in the patch 6/9
v2:
As Thomas suggested,
Reword some commit's description
Remove topology_smt_supported()
Remove topology_smt_threads_supported()
Introduce CONFIG_SMT_NUM_THREADS_DYNAMIC
Remove switch() in __store_smt_control()
Update kernel-parameters.txt

[1] https://lore.kernel.org/linuxppc-dev/[email protected]/
[2] https://lore.kernel.org/linuxppc-dev/[email protected]/


Laurent Dufour (2):
cpu/hotplug: remove dependancy against cpu_primary_thread_mask
cpu/SMT: Remove topology_smt_supported()

Michael Ellerman (8):
cpu/SMT: Move SMT prototypes into cpu_smt.h
cpu/SMT: Move smt/control simple exit cases earlier
cpu/SMT: Store the current/max number of threads
cpu/SMT: Create topology_smt_thread_allowed()
cpu/SMT: Allow enabling partial SMT states via sysfs
powerpc/pseries: Initialise CPU hotplug callbacks earlier
powerpc: Add HOTPLUG_SMT support
powerpc/pseries: Honour current SMT state when DLPAR onlining CPUs

.../ABI/testing/sysfs-devices-system-cpu | 1 +
.../admin-guide/kernel-parameters.txt | 4 +-
arch/Kconfig | 3 +
arch/powerpc/Kconfig | 2 +
arch/powerpc/include/asm/topology.h | 15 ++
arch/powerpc/kernel/smp.c | 8 +-
arch/powerpc/platforms/pseries/hotplug-cpu.c | 30 ++--
arch/powerpc/platforms/pseries/pseries.h | 2 +
arch/powerpc/platforms/pseries/setup.c | 2 +
arch/x86/include/asm/topology.h | 4 +-
arch/x86/kernel/cpu/common.c | 2 +-
arch/x86/kernel/smpboot.c | 8 -
include/linux/cpu.h | 25 +--
include/linux/cpu_smt.h | 33 ++++
kernel/cpu.c | 142 +++++++++++++-----
15 files changed, 196 insertions(+), 85 deletions(-)
create mode 100644 include/linux/cpu_smt.h

--
2.41.0



2023-07-05 14:58:49

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 04/10] cpu/SMT: Store the current/max number of threads

From: Michael Ellerman <[email protected]>

Some architectures allow partial SMT states at boot time, ie. when
not all SMT threads are brought online.

To support that the SMT code needs to know the maximum number of SMT
threads, and also the currently configured number.

The architecture code knows the max number of threads, so have the
architecture code pass that value to cpu_smt_set_num_threads(). Note that
although topology_max_smt_threads() exists, it is not configured early
enough to be used here. As architecture, like PowerPC, allows the threads
number to be set through the kernel command line, also pass that value.

Signed-off-by: Michael Ellerman <[email protected]>
[ldufour: slightly reword the commit message]
[ldufour: rename cpu_smt_check_topology and add a num_threads argument]
Signed-off-by: Laurent Dufour <[email protected]>
---
arch/x86/kernel/cpu/common.c | 2 +-
include/linux/cpu_smt.h | 8 ++++++--
kernel/cpu.c | 21 ++++++++++++++++++++-
3 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 52683fddafaf..12a48a85da3d 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -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: ");
diff --git a/include/linux/cpu_smt.h b/include/linux/cpu_smt.h
index 722c2e306fef..0c1664294b57 100644
--- a/include/linux/cpu_smt.h
+++ b/include/linux/cpu_smt.h
@@ -12,15 +12,19 @@ enum cpuhp_smt_control {

#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_check_topology(void);
+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_check_topology(void) { }
+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; }
diff --git a/kernel/cpu.c b/kernel/cpu.c
index b6fe170c93e9..d7dd535cb5b5 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -594,6 +594,8 @@ 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)
{
@@ -607,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)
{
+ WARN_ON(!num_threads || (num_threads > max_threads));
+
if (!topology_smt_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)
--
2.41.0


2023-07-05 14:58:57

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 07/10] cpu/SMT: Allow enabling partial SMT states via sysfs

From: Michael Ellerman <[email protected]>

Add support to the /sys/devices/system/cpu/smt/control interface for
enabling a specified number of SMT threads per core, including partial
SMT states where not all threads are brought online.

The current interface accepts "on" and "off", to enable either 1 or all
SMT threads per core.

This commit allows writing an integer, between 1 and the number of SMT
threads supported by the machine. Writing 1 is a synonym for "off", 2 or
more enables SMT with the specified number of threads.

When reading the file, if all threads are online "on" is returned, to
avoid changing behaviour for existing users. If some other number of
threads is online then the integer value is returned.

Architectures like x86 only supporting 1 thread or all threads, should not
define CONFIG_SMT_NUM_THREADS_DYNAMIC. Architecture supporting partial SMT
states, like PowerPC, should define it.

Signed-off-by: Michael Ellerman <[email protected]>
[ldufour: slightly reword the commit's description]
[ldufour: remove switch() in __store_smt_control()]
Reported-by: kernel test robot <[email protected]>
Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
[ldufour: fix build issue in control_show()]
Signed-off-by: Laurent Dufour <[email protected]>
---
.../ABI/testing/sysfs-devices-system-cpu | 1 +
kernel/cpu.c | 60 ++++++++++++++-----
2 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index ecd585ca2d50..6dba65fb1956 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -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
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 9a8d0685e055..7e8f1b044772 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -2876,11 +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;
+ int ctrlval, ret, num_threads, orig_threads;
+ bool force_off;

if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
return -EPERM;
@@ -2888,30 +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"))
+ if (sysfs_streq(buf, "on")) {
ctrlval = CPU_SMT_ENABLED;
- else if (sysfs_streq(buf, "off"))
+ num_threads = cpu_smt_max_threads;
+ } else if (sysfs_streq(buf, "off")) {
ctrlval = CPU_SMT_DISABLED;
- else if (sysfs_streq(buf, "forceoff"))
+ num_threads = 1;
+ } else if (sysfs_streq(buf, "forceoff")) {
ctrlval = CPU_SMT_FORCE_DISABLED;
- else
+ 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;
@@ -2939,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);
}

--
2.41.0


2023-07-05 15:07:08

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 03/10] cpu/SMT: Move smt/control simple exit cases earlier

From: Michael Ellerman <[email protected]>

Move the simple exit cases, ie. which don't depend on the value written,
earlier in the function. That makes it clearer that regardless of the
input those states can not be transitioned out of.

That does have a user-visible effect, in that the error returned will
now always be EPERM/ENODEV for those states, regardless of the value
written. Previously writing an invalid value would return EINVAL even
when in those states.

Signed-off-by: Michael Ellerman <[email protected]>
---
kernel/cpu.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/kernel/cpu.c b/kernel/cpu.c
index e02204c4675a..b6fe170c93e9 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -2841,6 +2841,12 @@ __store_smt_control(struct device *dev, struct device_attribute *attr,
{
int ctrlval, ret;

+ if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
+ return -EPERM;
+
+ if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
+ return -ENODEV;
+
if (sysfs_streq(buf, "on"))
ctrlval = CPU_SMT_ENABLED;
else if (sysfs_streq(buf, "off"))
@@ -2850,12 +2856,6 @@ __store_smt_control(struct device *dev, struct device_attribute *attr,
else
return -EINVAL;

- if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
- return -EPERM;
-
- if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
- return -ENODEV;
-
ret = lock_device_hotplug_sysfs();
if (ret)
return ret;
--
2.41.0


2023-07-05 15:08:09

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 01/10] cpu/hotplug: remove dependancy against cpu_primary_thread_mask

The commit 18415f33e2ac ("cpu/hotplug: Allow "parallel" bringup up to
CPUHP_BP_KICK_AP_STATE") introduce a dependancy against a global variable
cpu_primary_thread_mask exported by the X86 code. This variable is only
used when CONFIG_HOTPLUG_PARALLEL is set.

Since cpuhp_get_primary_thread_mask() and cpuhp_smt_aware() are only used
when CONFIG_HOTPLUG_PARALLEL is set, don't define them when it is not set.

There is no functional change introduce by that patch.

Cc: Thomas Gleixner <[email protected]>
Signed-off-by: Laurent Dufour <[email protected]>
---
kernel/cpu.c | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/kernel/cpu.c b/kernel/cpu.c
index 88a7ede322bd..03309f2f35a4 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -650,22 +650,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 +1779,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 topology_smt_supported();
+}
+
+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
--
2.41.0


2023-07-05 15:08:41

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 08/10] powerpc/pseries: Initialise CPU hotplug callbacks earlier

From: Michael Ellerman <[email protected]>

As part of the generic HOTPLUG_SMT code, there is support for disabling
secondary SMT threads at boot time, by passing "nosmt" on the kernel
command line.

The way that is implemented is the secondary threads are brought partly
online, and then taken back offline again. That is done to support x86
CPUs needing certain initialisation done on all threads. However powerpc
has similar needs, see commit d70a54e2d085 ("powerpc/powernv: Ignore
smt-enabled on Power8 and later").

For that to work the powerpc CPU hotplug callbacks need to be registered
before secondary CPUs are brought online, otherwise __cpu_disable()
fails due to smp_ops->cpu_disable being NULL.

So split the basic initialisation into pseries_cpu_hotplug_init() which
can be called early from setup_arch(). The DLPAR related initialisation
can still be done later, because it needs to do allocations.

Signed-off-by: Michael Ellerman <[email protected]>
---
arch/powerpc/platforms/pseries/hotplug-cpu.c | 22 ++++++++++++--------
arch/powerpc/platforms/pseries/pseries.h | 2 ++
arch/powerpc/platforms/pseries/setup.c | 2 ++
3 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 1a3cb313976a..61fb7cb00880 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -845,15 +845,9 @@ static struct notifier_block pseries_smp_nb = {
.notifier_call = pseries_smp_notifier,
};

-static int __init pseries_cpu_hotplug_init(void)
+void __init pseries_cpu_hotplug_init(void)
{
int qcss_tok;
- unsigned int node;
-
-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
- ppc_md.cpu_probe = dlpar_cpu_probe;
- ppc_md.cpu_release = dlpar_cpu_release;
-#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */

rtas_stop_self_token = rtas_function_token(RTAS_FN_STOP_SELF);
qcss_tok = rtas_function_token(RTAS_FN_QUERY_CPU_STOPPED_STATE);
@@ -862,12 +856,22 @@ static int __init pseries_cpu_hotplug_init(void)
qcss_tok == RTAS_UNKNOWN_SERVICE) {
printk(KERN_INFO "CPU Hotplug not supported by firmware "
"- disabling.\n");
- return 0;
+ return;
}

smp_ops->cpu_offline_self = pseries_cpu_offline_self;
smp_ops->cpu_disable = pseries_cpu_disable;
smp_ops->cpu_die = pseries_cpu_die;
+}
+
+static int __init pseries_dlpar_init(void)
+{
+ unsigned int node;
+
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
+ ppc_md.cpu_probe = dlpar_cpu_probe;
+ ppc_md.cpu_release = dlpar_cpu_release;
+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */

/* Processors can be added/removed only on LPAR */
if (firmware_has_feature(FW_FEATURE_LPAR)) {
@@ -886,4 +890,4 @@ static int __init pseries_cpu_hotplug_init(void)

return 0;
}
-machine_arch_initcall(pseries, pseries_cpu_hotplug_init);
+machine_arch_initcall(pseries, pseries_dlpar_init);
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index f8bce40ebd0c..f8893ba46e83 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -75,11 +75,13 @@ static inline int dlpar_hp_pmem(struct pseries_hp_errorlog *hp_elog)

#ifdef CONFIG_HOTPLUG_CPU
int dlpar_cpu(struct pseries_hp_errorlog *hp_elog);
+void pseries_cpu_hotplug_init(void);
#else
static inline int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
{
return -EOPNOTSUPP;
}
+static inline void pseries_cpu_hotplug_init(void) { }
#endif

/* PCI root bridge prepare function override for pseries */
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index e2a57cfa6c83..41451b76c6e5 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -816,6 +816,8 @@ static void __init pSeries_setup_arch(void)
/* Discover PIC type and setup ppc_md accordingly */
smp_init_pseries();

+ // Setup CPU hotplug callbacks
+ pseries_cpu_hotplug_init();

if (radix_enabled() && !mmu_has_feature(MMU_FTR_GTSE))
if (!firmware_has_feature(FW_FEATURE_RPT_INVALIDATE))
--
2.41.0


2023-07-05 15:12:23

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 10/10] powerpc/pseries: Honour current SMT state when DLPAR onlining CPUs

From: Michael Ellerman <[email protected]>

Integrate with the generic SMT support, so that when a CPU is DLPAR
onlined it is brought up with the correct SMT mode.

Signed-off-by: Michael Ellerman <[email protected]>
---
arch/powerpc/platforms/pseries/hotplug-cpu.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 61fb7cb00880..e62835a12d73 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -398,6 +398,14 @@ static int dlpar_online_cpu(struct device_node *dn)
for_each_present_cpu(cpu) {
if (get_hard_smp_processor_id(cpu) != thread)
continue;
+
+ if (!topology_is_primary_thread(cpu)) {
+ if (cpu_smt_control != CPU_SMT_ENABLED)
+ break;
+ if (!topology_smt_thread_allowed(cpu))
+ break;
+ }
+
cpu_maps_update_done();
find_and_update_cpu_nid(cpu);
rc = device_online(get_cpu_device(cpu));
--
2.41.0


2023-07-05 15:21:03

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 06/10] cpu/SMT: Create topology_smt_thread_allowed()

From: Michael Ellerman <[email protected]>

Some architectures allows partial SMT states, ie. when not all SMT
threads are brought online.

To support that, add an architecture helper which checks whether a given
CPU is allowed to be brought online depending on how many SMT threads are
currently enabled. Since this is only applicable to architecture supporting
partial SMT, only these architectures should select the new configuration
variable CONFIG_SMT_NUM_THREADS_DYNAMIC. For the other architectures, not
supporting the partial SMT states, there is no need to define
topology_cpu_smt_allowed(), the generic code assumed that all the threads
are allowed or only the primary ones.

Call the helper from cpu_smt_enable(), and cpu_smt_allowed() when SMT is
enabled, to check if the particular thread should be onlined. Notably,
also call it from cpu_smt_disable() if CPU_SMT_ENABLED, to allow
offlining some threads to move from a higher to lower number of threads
online.

Signed-off-by: Michael Ellerman <[email protected]>
Suggested-by: Thomas Gleixner <[email protected]>
[ldufour: slightly reword the commit's description]
[ldufour: introduce CONFIG_SMT_NUM_THREADS_DYNAMIC]
Signed-off-by: Laurent Dufour <[email protected]>
---
arch/Kconfig | 3 +++
kernel/cpu.c | 24 +++++++++++++++++++++++-
2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index aff2746c8af2..63c5d6a2022b 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -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
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 70add058e77b..9a8d0685e055 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -645,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))
@@ -2642,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;
@@ -2676,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;
--
2.41.0


2023-07-05 15:22:04

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 05/10] cpu/SMT: Remove topology_smt_supported()

Since the maximum number of threads is now passed to
cpu_smt_set_num_threads(), checking that value is enough to know if SMT is
supported.

Cc: Michael Ellerman <[email protected]>
Suggested-by: Thomas Gleixner <[email protected]>
Signed-off-by: Laurent Dufour <[email protected]>
---
arch/x86/include/asm/topology.h | 2 --
arch/x86/kernel/smpboot.c | 8 --------
kernel/cpu.c | 4 ++--
3 files changed, 2 insertions(+), 12 deletions(-)

diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index ae49ed4417d0..3235ba1e5b06 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -141,7 +141,6 @@ static inline int topology_max_smt_threads(void)
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)
@@ -164,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)
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index ed2d51960a7d..f8e709fd2cd5 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -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
diff --git a/kernel/cpu.c b/kernel/cpu.c
index d7dd535cb5b5..70add058e77b 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -621,7 +621,7 @@ void __init cpu_smt_set_num_threads(unsigned int num_threads,
{
WARN_ON(!num_threads || (num_threads > max_threads));

- if (!topology_smt_supported())
+ if (max_threads == 1)
cpu_smt_control = CPU_SMT_NOT_SUPPORTED;

cpu_smt_max_threads = max_threads;
@@ -1801,7 +1801,7 @@ early_param("cpuhp.parallel", parallel_bringup_parse_param);

static inline bool cpuhp_smt_aware(void)
{
- return topology_smt_supported();
+ return cpu_smt_max_threads > 1;
}

static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
--
2.41.0


2023-07-05 15:28:49

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 09/10] powerpc: Add HOTPLUG_SMT support

From: Michael Ellerman <[email protected]>

Add support for HOTPLUG_SMT, which enables the generic sysfs SMT support
files in /sys/devices/system/cpu/smt, as well as the "nosmt" boot
parameter.

Implement the recently added hooks to allow partial SMT states, allow
any number of threads per core.

Tie the config symbol to HOTPLUG_CPU, which enables it on the major
platforms that support SMT. If there are other platforms that want the
SMT support that can be tweaked in future.

Signed-off-by: Michael Ellerman <[email protected]>
[ldufour: pass current SMT level to cpu_smt_set_num_threads]
[ldufour: remove topology_smt_supported]
[ldufour: remove topology_smt_threads_supported]
[ldufour: select CONFIG_SMT_NUM_THREADS_DYNAMIC]
[ldufour: update kernel-parameters.txt]
Signed-off-by: Laurent Dufour <[email protected]>
---
Documentation/admin-guide/kernel-parameters.txt | 4 ++--
arch/powerpc/Kconfig | 2 ++
arch/powerpc/include/asm/topology.h | 15 +++++++++++++++
arch/powerpc/kernel/smp.c | 8 +++++++-
4 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 44bcaf791ce6..979f9bad59da 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3853,10 +3853,10 @@
nosmp [SMP] Tells an SMP kernel to act as a UP kernel,
and disable the IO APIC. legacy for "maxcpus=0".

- nosmt [KNL,MIPS,S390] Disable symmetric multithreading (SMT).
+ nosmt [KNL,MIPS,S390, PPC] Disable symmetric multithreading (SMT).
Equivalent to smt=1.

- [KNL,X86] Disable symmetric multithreading (SMT).
+ [KNL,X86,PPC] Disable symmetric multithreading (SMT).
nosmt=force: Force disable SMT, cannot be undone
via the sysfs control file.

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 0b1172cbeccb..aef38d2ca542 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -272,6 +272,8 @@ config PPC
select HAVE_SYSCALL_TRACEPOINTS
select HAVE_VIRT_CPU_ACCOUNTING
select HAVE_VIRT_CPU_ACCOUNTING_GEN
+ select HOTPLUG_SMT if HOTPLUG_CPU
+ select SMT_NUM_THREADS_DYNAMIC
select HUGETLB_PAGE_SIZE_VARIABLE if PPC_BOOK3S_64 && HUGETLB_PAGE
select IOMMU_HELPER if PPC64
select IRQ_DOMAIN
diff --git a/arch/powerpc/include/asm/topology.h b/arch/powerpc/include/asm/topology.h
index 8a4d4f4d9749..f4e6f2dd04b7 100644
--- a/arch/powerpc/include/asm/topology.h
+++ b/arch/powerpc/include/asm/topology.h
@@ -143,5 +143,20 @@ static inline int cpu_to_coregroup_id(int cpu)
#endif
#endif

+#ifdef CONFIG_HOTPLUG_SMT
+#include <linux/cpu_smt.h>
+#include <asm/cputhreads.h>
+
+static inline bool topology_is_primary_thread(unsigned int cpu)
+{
+ return cpu == cpu_first_thread_sibling(cpu);
+}
+
+static inline bool topology_smt_thread_allowed(unsigned int cpu)
+{
+ return cpu_thread_in_core(cpu) < cpu_smt_num_threads;
+}
+#endif
+
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_TOPOLOGY_H */
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index fbbb695bae3d..b9f0f8f11c37 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -1087,7 +1087,7 @@ static int __init init_big_cores(void)

void __init smp_prepare_cpus(unsigned int max_cpus)
{
- unsigned int cpu;
+ unsigned int cpu, num_threads;

DBG("smp_prepare_cpus\n");

@@ -1154,6 +1154,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus)

if (smp_ops && smp_ops->probe)
smp_ops->probe();
+
+ // Initalise the generic SMT topology support
+ num_threads = 1;
+ if (smt_enabled_at_boot)
+ num_threads = smt_enabled_at_boot;
+ cpu_smt_set_num_threads(num_threads, threads_per_core);
}

void smp_prepare_boot_cpu(void)
--
2.41.0


2023-07-05 15:39:52

by Laurent Dufour

[permalink] [raw]
Subject: [PATCH v4 02/10] cpu/SMT: Move SMT prototypes into cpu_smt.h

From: Michael Ellerman <[email protected]>

In order to export the cpuhp_smt_control enum as part of the interface
between generic and architecture code, the architecture code needs to
include asm/topology.h.

But that leads to circular header dependencies. So split the enum and
related declarations into a separate header.

Signed-off-by: Michael Ellerman <[email protected]>
[ldufour: rewording the commit's description]
Signed-off-by: Laurent Dufour <[email protected]>
---
arch/x86/include/asm/topology.h | 2 ++
include/linux/cpu.h | 25 +------------------------
include/linux/cpu_smt.h | 29 +++++++++++++++++++++++++++++
kernel/cpu.c | 1 +
4 files changed, 33 insertions(+), 24 deletions(-)
create mode 100644 include/linux/cpu_smt.h

diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index caf41c4869a0..ae49ed4417d0 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -136,6 +136,8 @@ 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);
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 6e6e57ec69e8..6b326a9e8191 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -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);

diff --git a/include/linux/cpu_smt.h b/include/linux/cpu_smt.h
new file mode 100644
index 000000000000..722c2e306fef
--- /dev/null
+++ b/include/linux/cpu_smt.h
@@ -0,0 +1,29 @@
+/* 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 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
+
+#endif /* _LINUX_CPU_SMT_H_ */
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 03309f2f35a4..e02204c4675a 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -592,6 +592,7 @@ 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;

void __init cpu_smt_disable(bool force)
--
2.41.0


2023-07-09 15:51:49

by Zhang, Rui

[permalink] [raw]
Subject: Re: [PATCH v4 00/10] Introduce SMT level and add PowerPC support

Hi, Laurent,

I ran into a boot hang regression with latest upstream code, and it
took me a while to bisect the offending commit and workaround it.

Now I have tested this patch series on an Intel RaptorLake Hybrid
platform (4 Pcores with HT and 4 Ecores without HT), and it works as
expected.

So, for patch 1~7 in this series,

Tested-by: Zhang Rui <[email protected]>

thanks,
rui

On Wed, 2023-07-05 at 16:51 +0200, Laurent Dufour wrote:
> I'm taking over the series Michael sent previously [1] which is
> smartly
> reviewing the initial series I sent [2].  This series is addressing
> the
> comments sent by Thomas and me on the Michael's one.
>
> Here is a short introduction to the issue this series is addressing:
>
> When a new CPU is added, the kernel is activating all its threads.
> This
> leads to weird, but functional, result when adding CPU on a SMT 4
> system
> for instance.
>
> Here the newly added CPU 1 has 8 threads while the other one has 4
> threads
> active (system has been booted with the 'smt-enabled=4' kernel
> option):
>
> ltcden3-lp12:~ # ppc64_cpu --info
> Core   0:    0*    1*    2*    3*    4     5     6     7
> Core   1:    8*    9*   10*   11*   12*   13*   14*   15*
>
> This mixed SMT level may confused end users and/or some applications.
>
> There is no SMT level recorded in the kernel (common code), neither
> in user
> space, as far as I know. Such a level is helpful when adding new CPU
> or
> when optimizing the energy efficiency (when reactivating CPUs).
>
> When SMP and HOTPLUG_SMT are defined, this series is adding a new SMT
> level
> (cpu_smt_num_threads) and few callbacks allowing the architecture
> code to
> fine control this value, setting a max and a "at boot" level, and
> controling whether a thread should be onlined or not.
>
> v4:
>   Rebase on top of 6.5's updates
>   Remove a dependancy against the X86's symbol
> cpu_primary_thread_mask
> v3:
>   Fix a build error in the patch 6/9
> v2:
>   As Thomas suggested,
>     Reword some commit's description
>     Remove topology_smt_supported()
>     Remove topology_smt_threads_supported()
>     Introduce CONFIG_SMT_NUM_THREADS_DYNAMIC
>     Remove switch() in __store_smt_control()
>   Update kernel-parameters.txt
>
> [1]
> https://lore.kernel.org/linuxppc-dev/[email protected]/
> [2]
> https://lore.kernel.org/linuxppc-dev/[email protected]/
>
>
> Laurent Dufour (2):
>   cpu/hotplug: remove dependancy against cpu_primary_thread_mask
>   cpu/SMT: Remove topology_smt_supported()
>
> Michael Ellerman (8):
>   cpu/SMT: Move SMT prototypes into cpu_smt.h
>   cpu/SMT: Move smt/control simple exit cases earlier
>   cpu/SMT: Store the current/max number of threads
>   cpu/SMT: Create topology_smt_thread_allowed()
>   cpu/SMT: Allow enabling partial SMT states via sysfs
>   powerpc/pseries: Initialise CPU hotplug callbacks earlier
>   powerpc: Add HOTPLUG_SMT support
>   powerpc/pseries: Honour current SMT state when DLPAR onlining CPUs
>
>  .../ABI/testing/sysfs-devices-system-cpu      |   1 +
>  .../admin-guide/kernel-parameters.txt         |   4 +-
>  arch/Kconfig                                  |   3 +
>  arch/powerpc/Kconfig                          |   2 +
>  arch/powerpc/include/asm/topology.h           |  15 ++
>  arch/powerpc/kernel/smp.c                     |   8 +-
>  arch/powerpc/platforms/pseries/hotplug-cpu.c  |  30 ++--
>  arch/powerpc/platforms/pseries/pseries.h      |   2 +
>  arch/powerpc/platforms/pseries/setup.c        |   2 +
>  arch/x86/include/asm/topology.h               |   4 +-
>  arch/x86/kernel/cpu/common.c                  |   2 +-
>  arch/x86/kernel/smpboot.c                     |   8 -
>  include/linux/cpu.h                           |  25 +--
>  include/linux/cpu_smt.h                       |  33 ++++
>  kernel/cpu.c                                  | 142 +++++++++++++---
> --
>  15 files changed, 196 insertions(+), 85 deletions(-)
>  create mode 100644 include/linux/cpu_smt.h
>

2023-07-10 09:23:12

by Laurent Dufour

[permalink] [raw]
Subject: Re: [PATCH v4 00/10] Introduce SMT level and add PowerPC support



Le 09/07/2023 à 17:25, Zhang, Rui a écrit :
> Hi, Laurent,
>
> I ran into a boot hang regression with latest upstream code, and it
> took me a while to bisect the offending commit and workaround it.
>
> Now I have tested this patch series on an Intel RaptorLake Hybrid
> platform (4 Pcores with HT and 4 Ecores without HT), and it works as
> expected.
>
> So, for patch 1~7 in this series,
>
> Tested-by: Zhang Rui <[email protected]>

Thanks Rui!

> thanks,
> rui
>
> On Wed, 2023-07-05 at 16:51 +0200, Laurent Dufour wrote:
>> I'm taking over the series Michael sent previously [1] which is
>> smartly
>> reviewing the initial series I sent [2].  This series is addressing
>> the
>> comments sent by Thomas and me on the Michael's one.
>>
>> Here is a short introduction to the issue this series is addressing:
>>
>> When a new CPU is added, the kernel is activating all its threads.
>> This
>> leads to weird, but functional, result when adding CPU on a SMT 4
>> system
>> for instance.
>>
>> Here the newly added CPU 1 has 8 threads while the other one has 4
>> threads
>> active (system has been booted with the 'smt-enabled=4' kernel
>> option):
>>
>> ltcden3-lp12:~ # ppc64_cpu --info
>> Core   0:    0*    1*    2*    3*    4     5     6     7
>> Core   1:    8*    9*   10*   11*   12*   13*   14*   15*
>>
>> This mixed SMT level may confused end users and/or some applications.
>>
>> There is no SMT level recorded in the kernel (common code), neither
>> in user
>> space, as far as I know. Such a level is helpful when adding new CPU
>> or
>> when optimizing the energy efficiency (when reactivating CPUs).
>>
>> When SMP and HOTPLUG_SMT are defined, this series is adding a new SMT
>> level
>> (cpu_smt_num_threads) and few callbacks allowing the architecture
>> code to
>> fine control this value, setting a max and a "at boot" level, and
>> controling whether a thread should be onlined or not.
>>
>> v4:
>>   Rebase on top of 6.5's updates
>>   Remove a dependancy against the X86's symbol
>> cpu_primary_thread_mask
>> v3:
>>   Fix a build error in the patch 6/9
>> v2:
>>   As Thomas suggested,
>>     Reword some commit's description
>>     Remove topology_smt_supported()
>>     Remove topology_smt_threads_supported()
>>     Introduce CONFIG_SMT_NUM_THREADS_DYNAMIC
>>     Remove switch() in __store_smt_control()
>>   Update kernel-parameters.txt
>>
>> [1]
>> https://lore.kernel.org/linuxppc-dev/[email protected]/
>> [2]
>> https://lore.kernel.org/linuxppc-dev/[email protected]/
>>
>>
>> Laurent Dufour (2):
>>   cpu/hotplug: remove dependancy against cpu_primary_thread_mask
>>   cpu/SMT: Remove topology_smt_supported()
>>
>> Michael Ellerman (8):
>>   cpu/SMT: Move SMT prototypes into cpu_smt.h
>>   cpu/SMT: Move smt/control simple exit cases earlier
>>   cpu/SMT: Store the current/max number of threads
>>   cpu/SMT: Create topology_smt_thread_allowed()
>>   cpu/SMT: Allow enabling partial SMT states via sysfs
>>   powerpc/pseries: Initialise CPU hotplug callbacks earlier
>>   powerpc: Add HOTPLUG_SMT support
>>   powerpc/pseries: Honour current SMT state when DLPAR onlining CPUs
>>
>>  .../ABI/testing/sysfs-devices-system-cpu      |   1 +
>>  .../admin-guide/kernel-parameters.txt         |   4 +-
>>  arch/Kconfig                                  |   3 +
>>  arch/powerpc/Kconfig                          |   2 +
>>  arch/powerpc/include/asm/topology.h           |  15 ++
>>  arch/powerpc/kernel/smp.c                     |   8 +-
>>  arch/powerpc/platforms/pseries/hotplug-cpu.c  |  30 ++--
>>  arch/powerpc/platforms/pseries/pseries.h      |   2 +
>>  arch/powerpc/platforms/pseries/setup.c        |   2 +
>>  arch/x86/include/asm/topology.h               |   4 +-
>>  arch/x86/kernel/cpu/common.c                  |   2 +-
>>  arch/x86/kernel/smpboot.c                     |   8 -
>>  include/linux/cpu.h                           |  25 +--
>>  include/linux/cpu_smt.h                       |  33 ++++
>>  kernel/cpu.c                                  | 142 +++++++++++++---
>> --
>>  15 files changed, 196 insertions(+), 85 deletions(-)
>>  create mode 100644 include/linux/cpu_smt.h
>>
>

Subject: [tip: smp/core] cpu/SMT: Allow enabling partial SMT states via sysfs

The following commit has been merged into the smp/core branch of tip:

Commit-ID: 7f48405c3c3437d578d0f1e4287aa0a3bfa5623f
Gitweb: https://git.kernel.org/tip/7f48405c3c3437d578d0f1e4287aa0a3bfa5623f
Author: Michael Ellerman <[email protected]>
AuthorDate: Wed, 05 Jul 2023 16:51:40 +02:00
Committer: Thomas Gleixner <[email protected]>
CommitterDate: Fri, 28 Jul 2023 09:53:37 +02:00

cpu/SMT: Allow enabling partial SMT states via sysfs

Add support to the /sys/devices/system/cpu/smt/control interface for
enabling a specified number of SMT threads per core, including partial
SMT states where not all threads are brought online.

The current interface accepts "on" and "off", to enable either 1 or all
SMT threads per core.

This commit allows writing an integer, between 1 and the number of SMT
threads supported by the machine. Writing 1 is a synonym for "off", 2 or
more enables SMT with the specified number of threads.

When reading the file, if all threads are online "on" is returned, to
avoid changing behaviour for existing users. If some other number of
threads is online then the integer value is returned.

Architectures like x86 only supporting 1 thread or all threads, should not
define CONFIG_SMT_NUM_THREADS_DYNAMIC. Architecture supporting partial SMT
states, like PowerPC, should define it.

[ ldufour: Slightly reword the commit's description ]
[ ldufour: Remove switch() in __store_smt_control() ]
[ ldufour: Rix build issue in control_show() ]

Reported-by: kernel test robot <[email protected]>
Signed-off-by: Michael Ellerman <[email protected]>
Signed-off-by: Laurent Dufour <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Tested-by: Zhang Rui <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
---
Documentation/ABI/testing/sysfs-devices-system-cpu | 1 +-
kernel/cpu.c | 60 +++++++++----
2 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index ecd585c..6dba65f 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -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
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 9a8d068..7e8f1b0 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -2876,11 +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;
+ int ctrlval, ret, num_threads, orig_threads;
+ bool force_off;

if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
return -EPERM;
@@ -2888,30 +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"))
+ if (sysfs_streq(buf, "on")) {
ctrlval = CPU_SMT_ENABLED;
- else if (sysfs_streq(buf, "off"))
+ num_threads = cpu_smt_max_threads;
+ } else if (sysfs_streq(buf, "off")) {
ctrlval = CPU_SMT_DISABLED;
- else if (sysfs_streq(buf, "forceoff"))
+ num_threads = 1;
+ } else if (sysfs_streq(buf, "forceoff")) {
ctrlval = CPU_SMT_FORCE_DISABLED;
- else
+ 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;
@@ -2939,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);
}


Subject: [tip: smp/core] cpu/SMT: Move smt/control simple exit cases earlier

The following commit has been merged into the smp/core branch of tip:

Commit-ID: c53361ce7d8771129c517dca529d2f2dc5bf04d1
Gitweb: https://git.kernel.org/tip/c53361ce7d8771129c517dca529d2f2dc5bf04d1
Author: Michael Ellerman <[email protected]>
AuthorDate: Wed, 05 Jul 2023 16:51:36 +02:00
Committer: Thomas Gleixner <[email protected]>
CommitterDate: Fri, 28 Jul 2023 09:53:36 +02:00

cpu/SMT: Move smt/control simple exit cases earlier

Move the simple exit cases, i.e. those which don't depend on the value
written, earlier in the function. That makes it clearer that regardless of
the input those states cannot be transitioned out of.

That does have a user-visible effect, in that the error returned will
now always be EPERM/ENODEV for those states, regardless of the value
written. Previously writing an invalid value would return EINVAL even
when in those states.

Signed-off-by: Michael Ellerman <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Tested-by: Zhang Rui <[email protected]>
Link: https://lore.kernel.org/r/[email protected]

---
kernel/cpu.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/kernel/cpu.c b/kernel/cpu.c
index e02204c..b6fe170 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -2841,6 +2841,12 @@ __store_smt_control(struct device *dev, struct device_attribute *attr,
{
int ctrlval, ret;

+ if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
+ return -EPERM;
+
+ if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
+ return -ENODEV;
+
if (sysfs_streq(buf, "on"))
ctrlval = CPU_SMT_ENABLED;
else if (sysfs_streq(buf, "off"))
@@ -2850,12 +2856,6 @@ __store_smt_control(struct device *dev, struct device_attribute *attr,
else
return -EINVAL;

- if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
- return -EPERM;
-
- if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED)
- return -ENODEV;
-
ret = lock_device_hotplug_sysfs();
if (ret)
return ret;

Subject: [tip: smp/core] cpu/SMT: Remove topology_smt_supported()

The following commit has been merged into the smp/core branch of tip:

Commit-ID: 91b4a7dbfe05ddb6fd3cf78cc11fb5ed64d3af90
Gitweb: https://git.kernel.org/tip/91b4a7dbfe05ddb6fd3cf78cc11fb5ed64d3af90
Author: Laurent Dufour <[email protected]>
AuthorDate: Wed, 05 Jul 2023 16:51:38 +02:00
Committer: Thomas Gleixner <[email protected]>
CommitterDate: Fri, 28 Jul 2023 09:53:37 +02:00

cpu/SMT: Remove topology_smt_supported()

Since the maximum number of threads is now passed to cpu_smt_set_num_threads(),
checking that value is enough to know whether SMT is supported.

Suggested-by: Thomas Gleixner <[email protected]>
Signed-off-by: Laurent Dufour <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Tested-by: Zhang Rui <[email protected]>
Link: https://lore.kernel.org/r/[email protected]

---
arch/x86/include/asm/topology.h | 2 --
arch/x86/kernel/smpboot.c | 8 --------
kernel/cpu.c | 4 ++--
3 files changed, 2 insertions(+), 12 deletions(-)

diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index ae49ed4..3235ba1 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -141,7 +141,6 @@ static inline int topology_max_smt_threads(void)
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)
@@ -164,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)
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index e1aa2cd..d4e897b 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -327,14 +327,6 @@ static void notrace start_secondary(void *unused)
}

/**
- * 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
*
diff --git a/kernel/cpu.c b/kernel/cpu.c
index d7dd535..70add05 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -621,7 +621,7 @@ void __init cpu_smt_set_num_threads(unsigned int num_threads,
{
WARN_ON(!num_threads || (num_threads > max_threads));

- if (!topology_smt_supported())
+ if (max_threads == 1)
cpu_smt_control = CPU_SMT_NOT_SUPPORTED;

cpu_smt_max_threads = max_threads;
@@ -1801,7 +1801,7 @@ early_param("cpuhp.parallel", parallel_bringup_parse_param);

static inline bool cpuhp_smt_aware(void)
{
- return topology_smt_supported();
+ return cpu_smt_max_threads > 1;
}

static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)

Subject: [tip: smp/core] cpu/hotplug: Remove dependancy against cpu_primary_thread_mask

The following commit has been merged into the smp/core branch of tip:

Commit-ID: 7a4dcb4a5de1214c4a59448a759e2e264c2c4473
Gitweb: https://git.kernel.org/tip/7a4dcb4a5de1214c4a59448a759e2e264c2c4473
Author: Laurent Dufour <[email protected]>
AuthorDate: Wed, 05 Jul 2023 16:51:34 +02:00
Committer: Thomas Gleixner <[email protected]>
CommitterDate: Fri, 28 Jul 2023 09:53:36 +02:00

cpu/hotplug: Remove dependancy against cpu_primary_thread_mask

The commit 18415f33e2ac ("cpu/hotplug: Allow "parallel" bringup up to
CPUHP_BP_KICK_AP_STATE") introduce a dependancy against a global variable
cpu_primary_thread_mask exported by the X86 code. This variable is only
used when CONFIG_HOTPLUG_PARALLEL is set.

Since cpuhp_get_primary_thread_mask() and cpuhp_smt_aware() are only used
when CONFIG_HOTPLUG_PARALLEL is set, don't define them when it is not set.

No functional change.

Signed-off-by: Laurent Dufour <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Tested-by: Zhang Rui <[email protected]>
Link: https://lore.kernel.org/r/[email protected]

---
kernel/cpu.c | 24 ++++++++++--------------
1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/kernel/cpu.c b/kernel/cpu.c
index 88a7ede..03309f2 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -650,22 +650,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 +1779,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 topology_smt_supported();
+}
+
+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

2023-07-28 08:37:10

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH v4 00/10] Introduce SMT level and add PowerPC support

Rui!

On Sun, Jul 09 2023 at 15:25, Rui Zhang wrote:
> I ran into a boot hang regression with latest upstream code, and it
> took me a while to bisect the offending commit and workaround it.

Where is the bug report and the analysis? And what's the workaround?

Thanks,

tglx

2023-07-28 08:39:31

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH v4 00/10] Introduce SMT level and add PowerPC support

Laurent, Michael!

On Wed, Jul 05 2023 at 16:51, Laurent Dufour wrote:
> I'm taking over the series Michael sent previously [1] which is smartly
> reviewing the initial series I sent [2]. This series is addressing the
> comments sent by Thomas and me on the Michael's one.

Thanks for getting this into shape.

I've merged it into:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git smp/core

and tagged it at patch 7 for consumption into the powerpc tree, so the
powerpc specific changes can be applied there on top:

git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git smp-core-for-ppc-23-07-28

Thanks,

tglx

Subject: [tip: smp/core] cpu/SMT: Create topology_smt_thread_allowed()

The following commit has been merged into the smp/core branch of tip:

Commit-ID: 38253464bc821d6de6bba81bb1412ebb36f6cbd1
Gitweb: https://git.kernel.org/tip/38253464bc821d6de6bba81bb1412ebb36f6cbd1
Author: Michael Ellerman <[email protected]>
AuthorDate: Wed, 05 Jul 2023 16:51:39 +02:00
Committer: Thomas Gleixner <[email protected]>
CommitterDate: Fri, 28 Jul 2023 09:53:37 +02:00

cpu/SMT: Create topology_smt_thread_allowed()

Some architectures allows partial SMT states, i.e. when not all SMT threads
are brought online.

To support that, add an architecture helper which checks whether a given
CPU is allowed to be brought online depending on how many SMT threads are
currently enabled. Since this is only applicable to architecture supporting
partial SMT, only these architectures should select the new configuration
variable CONFIG_SMT_NUM_THREADS_DYNAMIC. For the other architectures, not
supporting the partial SMT states, there is no need to define
topology_cpu_smt_allowed(), the generic code assumed that all the threads
are allowed or only the primary ones.

Call the helper from cpu_smt_enable(), and cpu_smt_allowed() when SMT is
enabled, to check if the particular thread should be onlined. Notably,
also call it from cpu_smt_disable() if CPU_SMT_ENABLED, to allow
offlining some threads to move from a higher to lower number of threads
online.

[ ldufour: Slightly reword the commit's description ]
[ ldufour: Introduce CONFIG_SMT_NUM_THREADS_DYNAMIC ]

Suggested-by: Thomas Gleixner <[email protected]>
Signed-off-by: Michael Ellerman <[email protected]>
Signed-off-by: Laurent Dufour <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Tested-by: Zhang Rui <[email protected]>
Link: https://lore.kernel.org/r/[email protected]

---
arch/Kconfig | 3 +++
kernel/cpu.c | 24 +++++++++++++++++++++++-
2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index aff2746..63c5d6a 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -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
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 70add05..9a8d068 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -645,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))
@@ -2642,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;
@@ -2676,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;

Subject: [tip: smp/core] cpu/SMT: Store the current/max number of threads

The following commit has been merged into the smp/core branch of tip:

Commit-ID: 447ae4ac41130a7f127c2581a5e816bb0800b560
Gitweb: https://git.kernel.org/tip/447ae4ac41130a7f127c2581a5e816bb0800b560
Author: Michael Ellerman <[email protected]>
AuthorDate: Wed, 05 Jul 2023 16:51:37 +02:00
Committer: Thomas Gleixner <[email protected]>
CommitterDate: Fri, 28 Jul 2023 09:53:37 +02:00

cpu/SMT: Store the current/max number of threads

Some architectures allow partial SMT states at boot time, ie. when not all
SMT threads are brought online.

To support that the SMT code needs to know the maximum number of SMT
threads, and also the currently configured number.

The architecture code knows the max number of threads, so have the
architecture code pass that value to cpu_smt_set_num_threads(). Note that
although topology_max_smt_threads() exists, it is not configured early
enough to be used here. As architecture, like PowerPC, allows the threads
number to be set through the kernel command line, also pass that value.

[ ldufour: Slightly reword the commit message ]
[ ldufour: Rename cpu_smt_check_topology and add a num_threads argument ]

Signed-off-by: Michael Ellerman <[email protected]>
Signed-off-by: Laurent Dufour <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Tested-by: Zhang Rui <[email protected]>
Link: https://lore.kernel.org/r/[email protected]

---
arch/x86/kernel/cpu/common.c | 2 +-
include/linux/cpu_smt.h | 8 ++++++--
kernel/cpu.c | 21 ++++++++++++++++++++-
3 files changed, 27 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 52683fd..12a48a8 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -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: ");
diff --git a/include/linux/cpu_smt.h b/include/linux/cpu_smt.h
index 722c2e3..0c16642 100644
--- a/include/linux/cpu_smt.h
+++ b/include/linux/cpu_smt.h
@@ -12,15 +12,19 @@ enum cpuhp_smt_control {

#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_check_topology(void);
+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_check_topology(void) { }
+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; }
diff --git a/kernel/cpu.c b/kernel/cpu.c
index b6fe170..d7dd535 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -594,6 +594,8 @@ 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)
{
@@ -607,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)
{
+ WARN_ON(!num_threads || (num_threads > max_threads));
+
if (!topology_smt_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)

Subject: [tip: smp/core] cpu/SMT: Move SMT prototypes into cpu_smt.h

The following commit has been merged into the smp/core branch of tip:

Commit-ID: 3f9169196be55590a794b52f49637561ddd1ba4f
Gitweb: https://git.kernel.org/tip/3f9169196be55590a794b52f49637561ddd1ba4f
Author: Michael Ellerman <[email protected]>
AuthorDate: Wed, 05 Jul 2023 16:51:35 +02:00
Committer: Thomas Gleixner <[email protected]>
CommitterDate: Fri, 28 Jul 2023 09:53:36 +02:00

cpu/SMT: Move SMT prototypes into cpu_smt.h

In order to export the cpuhp_smt_control enum as part of the interface
between generic and architecture code, the architecture code needs to
include asm/topology.h.

But that leads to circular header dependencies. So split the enum and
related declarations into a separate header.

[ ldufour: Reworded the commit's description ]

Signed-off-by: Michael Ellerman <[email protected]>
Signed-off-by: Laurent Dufour <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Tested-by: Zhang Rui <[email protected]>
Link: https://lore.kernel.org/r/[email protected]

---
arch/x86/include/asm/topology.h | 2 ++
include/linux/cpu.h | 25 +------------------------
include/linux/cpu_smt.h | 29 +++++++++++++++++++++++++++++
kernel/cpu.c | 1 +
4 files changed, 33 insertions(+), 24 deletions(-)
create mode 100644 include/linux/cpu_smt.h

diff --git a/arch/x86/include/asm/topology.h b/arch/x86/include/asm/topology.h
index caf41c4..ae49ed4 100644
--- a/arch/x86/include/asm/topology.h
+++ b/arch/x86/include/asm/topology.h
@@ -136,6 +136,8 @@ 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);
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index 6e6e57e..6b326a9 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -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);

diff --git a/include/linux/cpu_smt.h b/include/linux/cpu_smt.h
new file mode 100644
index 0000000..722c2e3
--- /dev/null
+++ b/include/linux/cpu_smt.h
@@ -0,0 +1,29 @@
+/* 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 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
+
+#endif /* _LINUX_CPU_SMT_H_ */
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 03309f2..e02204c 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -592,6 +592,7 @@ 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;

void __init cpu_smt_disable(bool force)

2023-07-28 15:31:02

by Zhang, Rui

[permalink] [raw]
Subject: Re: [PATCH v4 00/10] Introduce SMT level and add PowerPC support

Hi, Thomas,

On Fri, 2023-07-28 at 09:40 +0200, Thomas Gleixner wrote:
> Rui!
>
> On Sun, Jul 09 2023 at 15:25, Rui Zhang wrote:
> > I ran into a boot hang regression with latest upstream code, and it
> > took me a while to bisect the offending commit and workaround it.
>
> Where is the bug report and the analysis? And what's the workaround?

As it is an iwlwifi regression, I didn't paste the link here.

The regression was reported at
https://lore.kernel.org/all/[email protected]/

And it was fixed later by below commit in 6.5-rc2.

thanks,
rui

commit 12a89f0177092dbc2a1cb1d05a9790adbcea2309
Author: Johannes Berg <[email protected]>
AuthorDate: Mon Jul 10 16:50:39 2023 +0200
Commit: Jakub Kicinski <[email protected]>
CommitDate: Tue Jul 11 20:26:06 2023 -0700

wifi: iwlwifi: remove 'use_tfh' config to fix crash

This is equivalent to 'gen2', and it was always confusing to have
two identical config entries. The split config patch actually had
been originally developed after removing 'use_tfh" and didn't add
the use_tfh in the new configs as they'd later been copied to the
new files. Thus the easiest way to fix the init crash here now is
to just remove use_tfh (which is erroneously unset in most of the
configs now) and use 'gen2' in the code instead.

There's possibly still an unwind error in iwl_txq_gen2_init() as
it crashes if TXQ 0 fails to initialize, but we can deal with it
later since the original failure is due to the use_tfh confusion.

Tested-by: Xi Ruoyao <[email protected]>
Reported-and-tested-by: Niklāvs Koļesņikovs
<[email protected]>
Reported-and-tested-by: Jeff Chua <[email protected]>
Reported-and-tested-by: Zhang Rui <[email protected]>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=217622
Link:
https://lore.kernel.org/all/[email protected]/
Link:
https://lore.kernel.org/all/CAAJw_Zug6VCS5ZqTWaFSr9sd85k%3DtyPm9DEE%2BmV%3DAKoECZM%[email protected]/
Fixes: 19898ce9cf8a ("wifi: iwlwifi: split 22000.c into multiple
files")
Signed-off-by: Johannes Berg <[email protected]>
Link:
https://lore.kernel.org/r/[email protected]
Signed-off-by: Jakub Kicinski <[email protected]>

>
> Thanks,
>
>         tglx

2023-07-28 15:59:41

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [PATCH v4 00/10] Introduce SMT level and add PowerPC support

On Fri, Jul 28 2023 at 14:23, Rui Zhang wrote:
> On Fri, 2023-07-28 at 09:40 +0200, Thomas Gleixner wrote:
>> On Sun, Jul 09 2023 at 15:25, Rui Zhang wrote:
>> > I ran into a boot hang regression with latest upstream code, and it
>> > took me a while to bisect the offending commit and workaround it.
>>
>> Where is the bug report and the analysis? And what's the workaround?
>
> As it is an iwlwifi regression, I didn't paste the link here.
>
> The regression was reported at
> https://lore.kernel.org/all/[email protected]/
>
> And it was fixed later by below commit in 6.5-rc2.

Ah, ok. I was worried that you ran into issues with the parallel bootup
muck.

2023-07-31 13:25:41

by Laurent Dufour

[permalink] [raw]
Subject: Re: [PATCH v4 00/10] Introduce SMT level and add PowerPC support



Le 28/07/2023 à 09:58, Thomas Gleixner a écrit :
> Laurent, Michael!
>
> On Wed, Jul 05 2023 at 16:51, Laurent Dufour wrote:
>> I'm taking over the series Michael sent previously [1] which is smartly
>> reviewing the initial series I sent [2]. This series is addressing the
>> comments sent by Thomas and me on the Michael's one.
>
> Thanks for getting this into shape.
>
> I've merged it into:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git smp/core
>
> and tagged it at patch 7 for consumption into the powerpc tree, so the
> powerpc specific changes can be applied there on top:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git smp-core-for-ppc-23-07-28

Thanks Thomas!

2023-08-10 07:41:20

by Michael Ellerman

[permalink] [raw]
Subject: Re: [PATCH v4 00/10] Introduce SMT level and add PowerPC support

Thomas Gleixner <[email protected]> writes:
> Laurent, Michael!
>
> On Wed, Jul 05 2023 at 16:51, Laurent Dufour wrote:
>> I'm taking over the series Michael sent previously [1] which is smartly
>> reviewing the initial series I sent [2]. This series is addressing the
>> comments sent by Thomas and me on the Michael's one.
>
> Thanks for getting this into shape.
>
> I've merged it into:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git smp/core
>
> and tagged it at patch 7 for consumption into the powerpc tree, so the
> powerpc specific changes can be applied there on top:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git smp-core-for-ppc-23-07-28

Thanks. I've merged this and applied the powerpc patches on top.

I've left it sitting in my topic/cpu-smt branch for the build bots to
chew on:

https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/log/?h=topic/cpu-smt

I'll plan to merge it into my next in the next day or two.

cheers

2023-08-10 09:17:36

by Laurent Dufour

[permalink] [raw]
Subject: Re: [PATCH v4 00/10] Introduce SMT level and add PowerPC support

Le 10/08/2023 à 08:23, Michael Ellerman a écrit :
> Thomas Gleixner <[email protected]> writes:
>> Laurent, Michael!
>>
>> On Wed, Jul 05 2023 at 16:51, Laurent Dufour wrote:
>>> I'm taking over the series Michael sent previously [1] which is smartly
>>> reviewing the initial series I sent [2]. This series is addressing the
>>> comments sent by Thomas and me on the Michael's one.
>>
>> Thanks for getting this into shape.
>>
>> I've merged it into:
>>
>> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git smp/core
>>
>> and tagged it at patch 7 for consumption into the powerpc tree, so the
>> powerpc specific changes can be applied there on top:
>>
>> git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git smp-core-for-ppc-23-07-28
>
> Thanks. I've merged this and applied the powerpc patches on top.
>
> I've left it sitting in my topic/cpu-smt branch for the build bots to
> chew on:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/log/?h=topic/cpu-smt
>
> I'll plan to merge it into my next in the next day or two.

Thanks Michael!

2023-08-14 11:44:12

by Srikar Dronamraju

[permalink] [raw]
Subject: Re: [PATCH v4 09/10] powerpc: Add HOTPLUG_SMT support

* Laurent Dufour <[email protected]> [2023-07-05 16:51:42]:

> From: Michael Ellerman <[email protected]>
>
> Add support for HOTPLUG_SMT, which enables the generic sysfs SMT support
> files in /sys/devices/system/cpu/smt, as well as the "nosmt" boot
> parameter.
>
> Implement the recently added hooks to allow partial SMT states, allow
> any number of threads per core.
>
> Tie the config symbol to HOTPLUG_CPU, which enables it on the major
> platforms that support SMT. If there are other platforms that want the
> SMT support that can be tweaked in future.
>
> Signed-off-by: Michael Ellerman <[email protected]>
> [ldufour: pass current SMT level to cpu_smt_set_num_threads]
> [ldufour: remove topology_smt_supported]
> [ldufour: remove topology_smt_threads_supported]
> [ldufour: select CONFIG_SMT_NUM_THREADS_DYNAMIC]
> [ldufour: update kernel-parameters.txt]
> Signed-off-by: Laurent Dufour <[email protected]>

Looks good to me.

Reviewed-by: Srikar Dronamraju <[email protected]>

--
Thanks and Regards
Srikar Dronamraju

2023-08-14 12:16:15

by Srikar Dronamraju

[permalink] [raw]
Subject: Re: [PATCH v4 08/10] powerpc/pseries: Initialise CPU hotplug callbacks earlier

* Laurent Dufour <[email protected]> [2023-07-05 16:51:41]:

> From: Michael Ellerman <[email protected]>
>
> As part of the generic HOTPLUG_SMT code, there is support for disabling
> secondary SMT threads at boot time, by passing "nosmt" on the kernel
> command line.
>
> The way that is implemented is the secondary threads are brought partly
> online, and then taken back offline again. That is done to support x86
> CPUs needing certain initialisation done on all threads. However powerpc
> has similar needs, see commit d70a54e2d085 ("powerpc/powernv: Ignore
> smt-enabled on Power8 and later").
>
> For that to work the powerpc CPU hotplug callbacks need to be registered
> before secondary CPUs are brought online, otherwise __cpu_disable()
> fails due to smp_ops->cpu_disable being NULL.
>
> So split the basic initialisation into pseries_cpu_hotplug_init() which
> can be called early from setup_arch(). The DLPAR related initialisation
> can still be done later, because it needs to do allocations.
>

Looks good to me.

Reviewed-by: Srikar Dronamraju <[email protected]>

> Signed-off-by: Michael Ellerman <[email protected]>

--
Thanks and Regards
Srikar Dronamraju

2023-08-14 13:35:09

by Srikar Dronamraju

[permalink] [raw]
Subject: Re: [PATCH v4 10/10] powerpc/pseries: Honour current SMT state when DLPAR onlining CPUs

* Laurent Dufour <[email protected]> [2023-07-05 16:51:43]:

> From: Michael Ellerman <[email protected]>
>
> Integrate with the generic SMT support, so that when a CPU is DLPAR
> onlined it is brought up with the correct SMT mode.
>

Looks good to me.

Reviewed-by: Srikar Dronamraju <[email protected]>
> Signed-off-by: Michael Ellerman <[email protected]>
> ---
> arch/powerpc/platforms/pseries/hotplug-cpu.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>

--
Thanks and Regards
Srikar Dronamraju

2024-04-08 14:42:55

by Michal Suchánek

[permalink] [raw]
Subject: Re: [PATCH v4 07/10] cpu/SMT: Allow enabling partial SMT states via sysfs

Hello,

On Wed, Jul 05, 2023 at 04:51:40PM +0200, Laurent Dufour wrote:
> From: Michael Ellerman <[email protected]>
>
> Add support to the /sys/devices/system/cpu/smt/control interface for
> enabling a specified number of SMT threads per core, including partial
> SMT states where not all threads are brought online.
>
> The current interface accepts "on" and "off", to enable either 1 or all
> SMT threads per core.
>
> This commit allows writing an integer, between 1 and the number of SMT
> threads supported by the machine. Writing 1 is a synonym for "off", 2 or
> more enables SMT with the specified number of threads.
>
> When reading the file, if all threads are online "on" is returned, to
> avoid changing behaviour for existing users. If some other number of
> threads is online then the integer value is returned.
>
> Architectures like x86 only supporting 1 thread or all threads, should not
> define CONFIG_SMT_NUM_THREADS_DYNAMIC. Architecture supporting partial SMT
> states, like PowerPC, should define it.

This causes a regression:
https://groups.google.com/g/powerpc-utils-devel/c/wrwVzAAnRlI/m/5KJSoqP4BAAJ

The userspace code only changes the SMT mode of online CPUs (at lest one
thread is online) and does not touch offline CPUs.

Using this new interface offlined CPUs are onlined when SMT value is
set.

Would you look into special-casing the offline CPUs?

Thanks

Michal

>
> Signed-off-by: Michael Ellerman <[email protected]>
> [ldufour: slightly reword the commit's description]
> [ldufour: remove switch() in __store_smt_control()]
> Reported-by: kernel test robot <[email protected]>
> Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/
> [ldufour: fix build issue in control_show()]
> Signed-off-by: Laurent Dufour <[email protected]>
> ---
> .../ABI/testing/sysfs-devices-system-cpu | 1 +
> kernel/cpu.c | 60 ++++++++++++++-----
> 2 files changed, 45 insertions(+), 16 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
> index ecd585ca2d50..6dba65fb1956 100644
> --- a/Documentation/ABI/testing/sysfs-devices-system-cpu
> +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
> @@ -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
> diff --git a/kernel/cpu.c b/kernel/cpu.c
> index 9a8d0685e055..7e8f1b044772 100644
> --- a/kernel/cpu.c
> +++ b/kernel/cpu.c
> @@ -2876,11 +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;
> + int ctrlval, ret, num_threads, orig_threads;
> + bool force_off;
>
> if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)
> return -EPERM;
> @@ -2888,30 +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"))
> + if (sysfs_streq(buf, "on")) {
> ctrlval = CPU_SMT_ENABLED;
> - else if (sysfs_streq(buf, "off"))
> + num_threads = cpu_smt_max_threads;
> + } else if (sysfs_streq(buf, "off")) {
> ctrlval = CPU_SMT_DISABLED;
> - else if (sysfs_streq(buf, "forceoff"))
> + num_threads = 1;
> + } else if (sysfs_streq(buf, "forceoff")) {
> ctrlval = CPU_SMT_FORCE_DISABLED;
> - else
> + 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;
> @@ -2939,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);
> }
>
> --
> 2.41.0
>