diff options
Diffstat (limited to 'arch/x86/kernel/smp.c')
| -rw-r--r-- | arch/x86/kernel/smp.c | 51 | 
1 files changed, 40 insertions, 11 deletions
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 13f33ea8cca..ec1de97600e 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -150,14 +150,40 @@ void native_send_call_func_ipi(const struct cpumask *mask)   * this function calls the 'stop' function on all other CPUs in the system.   */ +asmlinkage void smp_reboot_interrupt(void) +{ +	ack_APIC_irq(); +	irq_enter(); +	stop_this_cpu(NULL); +	irq_exit(); +} +  static void native_smp_send_stop(void)  {  	unsigned long flags; +	unsigned long wait;  	if (reboot_force)  		return; -	smp_call_function(stop_this_cpu, NULL, 0); +	/* +	 * Use an own vector here because smp_call_function +	 * does lots of things not suitable in a panic situation. +	 * On most systems we could also use an NMI here, +	 * but there are a few systems around where NMI +	 * is problematic so stay with an non NMI for now +	 * (this implies we cannot stop CPUs spinning with irq off +	 * currently) +	 */ +	if (num_online_cpus() > 1) { +		apic->send_IPI_allbutself(REBOOT_VECTOR); + +		/* Don't wait longer than a second */ +		wait = USEC_PER_SEC; +		while (num_online_cpus() > 1 && wait--) +			udelay(1); +	} +  	local_irq_save(flags);  	disable_local_APIC();  	local_irq_restore(flags); @@ -172,6 +198,9 @@ void smp_reschedule_interrupt(struct pt_regs *regs)  {  	ack_APIC_irq();  	inc_irq_stat(irq_resched_count); +	/* +	 * KVM uses this interrupt to force a cpu out of guest mode +	 */  }  void smp_call_function_interrupt(struct pt_regs *regs) @@ -193,19 +222,19 @@ void smp_call_function_single_interrupt(struct pt_regs *regs)  }  struct smp_ops smp_ops = { -	.smp_prepare_boot_cpu = native_smp_prepare_boot_cpu, -	.smp_prepare_cpus = native_smp_prepare_cpus, -	.smp_cpus_done = native_smp_cpus_done, +	.smp_prepare_boot_cpu	= native_smp_prepare_boot_cpu, +	.smp_prepare_cpus	= native_smp_prepare_cpus, +	.smp_cpus_done		= native_smp_cpus_done, -	.smp_send_stop = native_smp_send_stop, -	.smp_send_reschedule = native_smp_send_reschedule, +	.smp_send_stop		= native_smp_send_stop, +	.smp_send_reschedule	= native_smp_send_reschedule, -	.cpu_up = native_cpu_up, -	.cpu_die = native_cpu_die, -	.cpu_disable = native_cpu_disable, -	.play_dead = native_play_dead, +	.cpu_up			= native_cpu_up, +	.cpu_die		= native_cpu_die, +	.cpu_disable		= native_cpu_disable, +	.play_dead		= native_play_dead, -	.send_call_func_ipi = native_send_call_func_ipi, +	.send_call_func_ipi	= native_send_call_func_ipi,  	.send_call_func_single_ipi = native_send_call_func_single_ipi,  };  EXPORT_SYMBOL_GPL(smp_ops);  |