diff options
| author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-03-19 17:02:01 -0700 | 
|---|---|---|
| committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2012-03-19 17:02:01 -0700 | 
| commit | 10ce3cc919f50c2043b41ca968b43c26a3672600 (patch) | |
| tree | ea409366a5208aced495bc0516a08b81fd43222e /arch/x86/kernel/cpu/mcheck/mce-inject.c | |
| parent | 24e3e5ae1e4c2a3a32f5b1f96b4e3fd721806acd (diff) | |
| parent | 5c6a7a62c130afef3d61c1dee153012231ff5cd9 (diff) | |
Merge branch 'next' into for-linus
Diffstat (limited to 'arch/x86/kernel/cpu/mcheck/mce-inject.c')
| -rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce-inject.c | 34 | 
1 files changed, 30 insertions, 4 deletions
| diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c index 319882ef848..fc4beb39357 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-inject.c +++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c @@ -17,6 +17,7 @@  #include <linux/kernel.h>  #include <linux/string.h>  #include <linux/fs.h> +#include <linux/preempt.h>  #include <linux/smp.h>  #include <linux/notifier.h>  #include <linux/kdebug.h> @@ -92,6 +93,18 @@ static int mce_raise_notify(unsigned int cmd, struct pt_regs *regs)  	return NMI_HANDLED;  } +static void mce_irq_ipi(void *info) +{ +	int cpu = smp_processor_id(); +	struct mce *m = &__get_cpu_var(injectm); + +	if (cpumask_test_cpu(cpu, mce_inject_cpumask) && +			m->inject_flags & MCJ_EXCEPTION) { +		cpumask_clear_cpu(cpu, mce_inject_cpumask); +		raise_exception(m, NULL); +	} +} +  /* Inject mce on current CPU */  static int raise_local(void)  { @@ -139,9 +152,10 @@ static void raise_mce(struct mce *m)  		return;  #ifdef CONFIG_X86_LOCAL_APIC -	if (m->inject_flags & MCJ_NMI_BROADCAST) { +	if (m->inject_flags & (MCJ_IRQ_BRAODCAST | MCJ_NMI_BROADCAST)) {  		unsigned long start;  		int cpu; +  		get_online_cpus();  		cpumask_copy(mce_inject_cpumask, cpu_online_mask);  		cpumask_clear_cpu(get_cpu(), mce_inject_cpumask); @@ -151,13 +165,25 @@ static void raise_mce(struct mce *m)  			    MCJ_CTX(mcpu->inject_flags) != MCJ_CTX_RANDOM)  				cpumask_clear_cpu(cpu, mce_inject_cpumask);  		} -		if (!cpumask_empty(mce_inject_cpumask)) -			apic->send_IPI_mask(mce_inject_cpumask, NMI_VECTOR); +		if (!cpumask_empty(mce_inject_cpumask)) { +			if (m->inject_flags & MCJ_IRQ_BRAODCAST) { +				/* +				 * don't wait because mce_irq_ipi is necessary +				 * to be sync with following raise_local +				 */ +				preempt_disable(); +				smp_call_function_many(mce_inject_cpumask, +					mce_irq_ipi, NULL, 0); +				preempt_enable(); +			} else if (m->inject_flags & MCJ_NMI_BROADCAST) +				apic->send_IPI_mask(mce_inject_cpumask, +						NMI_VECTOR); +		}  		start = jiffies;  		while (!cpumask_empty(mce_inject_cpumask)) {  			if (!time_before(jiffies, start + 2*HZ)) {  				printk(KERN_ERR -				"Timeout waiting for mce inject NMI %lx\n", +				"Timeout waiting for mce inject %lx\n",  					*cpumask_bits(mce_inject_cpumask));  				break;  			} | 
