diff options
Diffstat (limited to 'arch/x86/kernel/process.c')
| -rw-r--r-- | arch/x86/kernel/process.c | 28 | 
1 files changed, 24 insertions, 4 deletions
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index dac41a0072ea..ff9b80a0e3e3 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -759,15 +759,26 @@ bool xen_set_default_idle(void)  }  #endif +struct cpumask cpus_stop_mask; +  void __noreturn stop_this_cpu(void *dummy)  { +	struct cpuinfo_x86 *c = this_cpu_ptr(&cpu_info); +	unsigned int cpu = smp_processor_id(); +  	local_irq_disable(); +  	/* -	 * Remove this CPU: +	 * Remove this CPU from the online mask and disable it +	 * unconditionally. This might be redundant in case that the reboot +	 * vector was handled late and stop_other_cpus() sent an NMI. +	 * +	 * According to SDM and APM NMIs can be accepted even after soft +	 * disabling the local APIC.  	 */ -	set_cpu_online(smp_processor_id(), false); +	set_cpu_online(cpu, false);  	disable_local_APIC(); -	mcheck_cpu_clear(this_cpu_ptr(&cpu_info)); +	mcheck_cpu_clear(c);  	/*  	 * Use wbinvd on processors that support SME. This provides support @@ -781,8 +792,17 @@ void __noreturn stop_this_cpu(void *dummy)  	 * Test the CPUID bit directly because the machine might've cleared  	 * X86_FEATURE_SME due to cmdline options.  	 */ -	if (cpuid_eax(0x8000001f) & BIT(0)) +	if (c->extended_cpuid_level >= 0x8000001f && (cpuid_eax(0x8000001f) & BIT(0)))  		native_wbinvd(); + +	/* +	 * This brings a cache line back and dirties it, but +	 * native_stop_other_cpus() will overwrite cpus_stop_mask after it +	 * observed that all CPUs reported stop. This write will invalidate +	 * the related cache line on this CPU. +	 */ +	cpumask_clear_cpu(cpu, &cpus_stop_mask); +  	for (;;) {  		/*  		 * Use native_halt() so that memory contents don't change  |