Skip to content

Commit

Permalink
cpu/hotplug: Boot HT siblings at least once
Browse files Browse the repository at this point in the history
Due to the way Machine Check Exceptions work on X86 hyperthreads it's
required to boot up _all_ logical cores at least once in order to set the
CR4.MCE bit.

So instead of ignoring the sibling threads right away, let them boot up
once so they can configure themselves. After they came out of the initial
boot stage check whether its a "secondary" sibling and cancel the operation
which puts the CPU back into offline state.

Reported-by: Dave Hansen <dave.hansen@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Tony Luck <tony.luck@intel.com>
  • Loading branch information
Thomas Gleixner committed Jul 2, 2018
1 parent 506a66f commit 0cc3cd2
Showing 1 changed file with 48 additions and 24 deletions.
72 changes: 48 additions & 24 deletions kernel/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct cpuhp_cpu_state {
bool rollback;
bool single;
bool bringup;
bool booted_once;
struct hlist_node *node;
struct hlist_node *last;
enum cpuhp_state cb_state;
Expand Down Expand Up @@ -342,6 +343,40 @@ void cpu_hotplug_enable(void)
EXPORT_SYMBOL_GPL(cpu_hotplug_enable);
#endif /* CONFIG_HOTPLUG_CPU */

#ifdef CONFIG_HOTPLUG_SMT
enum cpuhp_smt_control cpu_smt_control __read_mostly = CPU_SMT_ENABLED;

static int __init smt_cmdline_disable(char *str)
{
cpu_smt_control = CPU_SMT_DISABLED;
if (str && !strcmp(str, "force")) {
pr_info("SMT: Force disabled\n");
cpu_smt_control = CPU_SMT_FORCE_DISABLED;
}
return 0;
}
early_param("nosmt", smt_cmdline_disable);

static inline bool cpu_smt_allowed(unsigned int cpu)
{
if (cpu_smt_control == CPU_SMT_ENABLED)
return true;

if (topology_is_primary_thread(cpu))
return true;

/*
* On x86 it's required to boot all logical CPUs at least once so
* that the init code can get a chance to set CR4.MCE on each
* CPU. Otherwise, a broadacasted MCE observing CR4.MCE=0b on any
* core will shutdown the machine.
*/
return !per_cpu(cpuhp_state, cpu).booted_once;
}
#else
static inline bool cpu_smt_allowed(unsigned int cpu) { return true; }
#endif

static inline enum cpuhp_state
cpuhp_set_state(struct cpuhp_cpu_state *st, enum cpuhp_state target)
{
Expand Down Expand Up @@ -422,6 +457,16 @@ static int bringup_wait_for_ap(unsigned int cpu)
stop_machine_unpark(cpu);
kthread_unpark(st->thread);

/*
* SMT soft disabling on X86 requires to bring the CPU out of the
* BIOS 'wait for SIPI' state in order to set the CR4.MCE bit. The
* CPU marked itself as booted_once in cpu_notify_starting() so the
* cpu_smt_allowed() check will now return false if this is not the
* primary sibling.
*/
if (!cpu_smt_allowed(cpu))
return -ECANCELED;

if (st->target <= CPUHP_AP_ONLINE_IDLE)
return 0;

Expand Down Expand Up @@ -933,29 +978,6 @@ EXPORT_SYMBOL(cpu_down);
#define takedown_cpu NULL
#endif /*CONFIG_HOTPLUG_CPU*/

#ifdef CONFIG_HOTPLUG_SMT
enum cpuhp_smt_control cpu_smt_control __read_mostly = CPU_SMT_ENABLED;

static int __init smt_cmdline_disable(char *str)
{
cpu_smt_control = CPU_SMT_DISABLED;
if (str && !strcmp(str, "force")) {
pr_info("SMT: Force disabled\n");
cpu_smt_control = CPU_SMT_FORCE_DISABLED;
}
return 0;
}
early_param("nosmt", smt_cmdline_disable);

static inline bool cpu_smt_allowed(unsigned int cpu)
{
return cpu_smt_control == CPU_SMT_ENABLED ||
topology_is_primary_thread(cpu);
}
#else
static inline bool cpu_smt_allowed(unsigned int cpu) { return true; }
#endif

/**
* notify_cpu_starting(cpu) - Invoke the callbacks on the starting CPU
* @cpu: cpu that just started
Expand All @@ -970,6 +992,7 @@ void notify_cpu_starting(unsigned int cpu)
int ret;

rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */
st->booted_once = true;
while (st->state < target) {
st->state++;
ret = cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL);
Expand Down Expand Up @@ -2180,5 +2203,6 @@ void __init boot_cpu_init(void)
*/
void __init boot_cpu_state_init(void)
{
per_cpu_ptr(&cpuhp_state, smp_processor_id())->state = CPUHP_ONLINE;
this_cpu_write(cpuhp_state.booted_once, true);
this_cpu_write(cpuhp_state.state, CPUHP_ONLINE);
}

0 comments on commit 0cc3cd2

Please sign in to comment.