x86: add IRQ context simulation in module mce-inject
mce-inject provides a mechanism to simulate errors so that test scripts can check for correct operation of the kernel without requiring any specialized hardware to create rare events. The existing code can simulate events in normal process context and also in NMI context - but not in IRQ context. This patch fills that gap. Link: https://lkml.org/lkml/2011/12/7/537 Signed-off-by: Chen Gong <gong.chen@linux.intel.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
This commit is contained in:
parent
dc47ce90c3
commit
2c29d9dd57
|
@ -50,10 +50,11 @@
|
|||
#define MCJ_CTX_MASK 3
|
||||
#define MCJ_CTX(flags) ((flags) & MCJ_CTX_MASK)
|
||||
#define MCJ_CTX_RANDOM 0 /* inject context: random */
|
||||
#define MCJ_CTX_PROCESS 1 /* inject context: process */
|
||||
#define MCJ_CTX_IRQ 2 /* inject context: IRQ */
|
||||
#define MCJ_NMI_BROADCAST 4 /* do NMI broadcasting */
|
||||
#define MCJ_EXCEPTION 8 /* raise as exception */
|
||||
#define MCJ_CTX_PROCESS 0x1 /* inject context: process */
|
||||
#define MCJ_CTX_IRQ 0x2 /* inject context: IRQ */
|
||||
#define MCJ_NMI_BROADCAST 0x4 /* do NMI broadcasting */
|
||||
#define MCJ_EXCEPTION 0x8 /* raise as exception */
|
||||
#define MCJ_IRQ_BRAODCAST 0x10 /* do IRQ broadcasting */
|
||||
|
||||
/* Fields are zero when not available */
|
||||
struct mce {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue