| From foo@baz Tue Aug 14 16:14:56 CEST 2018 |
| From: Thomas Gleixner <tglx@linutronix.de> |
| Date: Tue, 7 Aug 2018 08:19:57 +0200 |
| Subject: cpu/hotplug: Fix SMT supported evaluation |
| |
| From: Thomas Gleixner <tglx@linutronix.de> |
| |
| commit bc2d8d262cba5736332cbc866acb11b1c5748aa9 upstream |
| |
| Josh reported that the late SMT evaluation in cpu_smt_state_init() sets |
| cpu_smt_control to CPU_SMT_NOT_SUPPORTED in case that 'nosmt' was supplied |
| on the kernel command line as it cannot differentiate between SMT disabled |
| by BIOS and SMT soft disable via 'nosmt'. That wreckages the state and |
| makes the sysfs interface unusable. |
| |
| Rework this so that during bringup of the non boot CPUs the availability of |
| SMT is determined in cpu_smt_allowed(). If a newly booted CPU is not a |
| 'primary' thread then set the local cpu_smt_available marker and evaluate |
| this explicitely right after the initial SMP bringup has finished. |
| |
| SMT evaulation on x86 is a trainwreck as the firmware has all the |
| information _before_ booting the kernel, but there is no interface to query |
| it. |
| |
| Fixes: 73d5e2b47264 ("cpu/hotplug: detect SMT disabled by BIOS") |
| Reported-by: Josh Poimboeuf <jpoimboe@redhat.com> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| arch/x86/kernel/cpu/bugs.c | 2 +- |
| include/linux/cpu.h | 2 ++ |
| kernel/cpu.c | 41 ++++++++++++++++++++++++++++------------- |
| kernel/smp.c | 2 ++ |
| 4 files changed, 33 insertions(+), 14 deletions(-) |
| |
| --- a/arch/x86/kernel/cpu/bugs.c |
| +++ b/arch/x86/kernel/cpu/bugs.c |
| @@ -61,7 +61,7 @@ void __init check_bugs(void) |
| * identify_boot_cpu() initialized SMT support information, let the |
| * core code know. |
| */ |
| - cpu_smt_check_topology(); |
| + cpu_smt_check_topology_early(); |
| |
| if (!IS_ENABLED(CONFIG_SMP)) { |
| pr_info("CPU: "); |
| --- a/include/linux/cpu.h |
| +++ b/include/linux/cpu.h |
| @@ -267,10 +267,12 @@ enum cpuhp_smt_control { |
| #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_early(void); |
| extern void cpu_smt_check_topology(void); |
| #else |
| # define cpu_smt_control (CPU_SMT_ENABLED) |
| static inline void cpu_smt_disable(bool force) { } |
| +static inline void cpu_smt_check_topology_early(void) { } |
| static inline void cpu_smt_check_topology(void) { } |
| #endif |
| |
| --- a/kernel/cpu.c |
| +++ b/kernel/cpu.c |
| @@ -360,6 +360,8 @@ EXPORT_SYMBOL_GPL(cpu_hotplug_enable); |
| enum cpuhp_smt_control cpu_smt_control __read_mostly = CPU_SMT_ENABLED; |
| EXPORT_SYMBOL_GPL(cpu_smt_control); |
| |
| +static bool cpu_smt_available __read_mostly; |
| + |
| void __init cpu_smt_disable(bool force) |
| { |
| if (cpu_smt_control == CPU_SMT_FORCE_DISABLED || |
| @@ -376,14 +378,28 @@ void __init cpu_smt_disable(bool force) |
| |
| /* |
| * The decision whether SMT is supported can only be done after the full |
| - * CPU identification. Called from architecture code. |
| + * CPU identification. Called from architecture code before non boot CPUs |
| + * are brought up. |
| */ |
| -void __init cpu_smt_check_topology(void) |
| +void __init cpu_smt_check_topology_early(void) |
| { |
| if (!topology_smt_supported()) |
| cpu_smt_control = CPU_SMT_NOT_SUPPORTED; |
| } |
| |
| +/* |
| + * If SMT was disabled by BIOS, detect it here, after the CPUs have been |
| + * brought online. This ensures the smt/l1tf sysfs entries are consistent |
| + * with reality. cpu_smt_available is set to true during the bringup of non |
| + * boot CPUs when a SMT sibling is detected. Note, this may overwrite |
| + * cpu_smt_control's previous setting. |
| + */ |
| +void __init cpu_smt_check_topology(void) |
| +{ |
| + if (!cpu_smt_available) |
| + cpu_smt_control = CPU_SMT_NOT_SUPPORTED; |
| +} |
| + |
| static int __init smt_cmdline_disable(char *str) |
| { |
| cpu_smt_disable(str && !strcmp(str, "force")); |
| @@ -393,10 +409,18 @@ early_param("nosmt", smt_cmdline_disable |
| |
| static inline bool cpu_smt_allowed(unsigned int cpu) |
| { |
| - if (cpu_smt_control == CPU_SMT_ENABLED) |
| + if (topology_is_primary_thread(cpu)) |
| return true; |
| |
| - if (topology_is_primary_thread(cpu)) |
| + /* |
| + * If the CPU is not a 'primary' thread and the booted_once bit is |
| + * set then the processor has SMT support. Store this information |
| + * for the late check of SMT support in cpu_smt_check_topology(). |
| + */ |
| + if (per_cpu(cpuhp_state, cpu).booted_once) |
| + cpu_smt_available = true; |
| + |
| + if (cpu_smt_control == CPU_SMT_ENABLED) |
| return true; |
| |
| /* |
| @@ -2063,15 +2087,6 @@ static const struct attribute_group cpuh |
| |
| static int __init cpu_smt_state_init(void) |
| { |
| - /* |
| - * If SMT was disabled by BIOS, detect it here, after the CPUs have |
| - * been brought online. This ensures the smt/l1tf sysfs entries are |
| - * consistent with reality. Note this may overwrite cpu_smt_control's |
| - * previous setting. |
| - */ |
| - if (topology_max_smt_threads() == 1) |
| - cpu_smt_control = CPU_SMT_NOT_SUPPORTED; |
| - |
| return sysfs_create_group(&cpu_subsys.dev_root->kobj, |
| &cpuhp_smt_attr_group); |
| } |
| --- a/kernel/smp.c |
| +++ b/kernel/smp.c |
| @@ -564,6 +564,8 @@ void __init smp_init(void) |
| cpu_up(cpu); |
| } |
| |
| + /* Final decision about SMT support */ |
| + cpu_smt_check_topology(); |
| /* Any cleanup work */ |
| smp_announce(); |
| smp_cpus_done(setup_max_cpus); |