[PATCH 4/4] mce-inject: support injecting multiple error to a CPU

From: Hidetoshi Seto
Date: Fri Oct 09 2009 - 01:48:39 EST


There is only one register set in structure mce_fake_banks, so
we cannot inject more than one event to a CPU. For example, we
cannot emulate situation that bank 1 of CPU X has a error while
bank 3 of same CPU X has an another error.

This patch make mce_fake_banks to have a list of register set,
and allow us to test more various error combination.

Signed-off-by: Hidetoshi Seto <seto.hidetoshi@xxxxxxxxxxxxxx>
---
arch/x86/include/asm/mce.h | 6 +++++
arch/x86/kernel/cpu/mcheck/mce-inject.c | 32 +++++++++++++++++++++++++++---
arch/x86/kernel/cpu/mcheck/mce.c | 22 ++++++++++++++------
3 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 0668044..8776ab1 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -244,6 +244,12 @@ struct mce_fake_banks {

__u8 inject_flags; /* software inject flags */

+ struct list_head list;
+};
+
+struct mce_fake_bank {
+ struct list_head list;
+ __u8 loaded;
__u8 bank;
__u64 status;
__u64 misc;
diff --git a/arch/x86/kernel/cpu/mcheck/mce-inject.c b/arch/x86/kernel/cpu/mcheck/mce-inject.c
index 6275318..943fc93 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-inject.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-inject.c
@@ -29,15 +29,30 @@
static void inject_mce(struct mce *m)
{
struct mce_fake_banks *banks = &per_cpu(mce_fake_banks, m->extcpu);
+ struct mce_fake_bank *b, *temp;

banks->mcgstatus = m->mcgstatus;
banks->ip = m->ip;
banks->cs = m->cs;
banks->inject_flags = m->inject_flags;
- banks->bank = m->bank;
- banks->status = m->status;
- banks->addr = m->addr;
- banks->misc = m->misc;
+
+ list_for_each_entry(temp, &banks->list, list) {
+ if (temp->bank == m->bank)
+ b = temp;
+ }
+ if (!b) {
+ b = kzalloc(sizeof(struct mce_fake_bank), GFP_KERNEL);
+ if (!b)
+ return; /* -ENOMEM */
+ INIT_LIST_HEAD(&b->list);
+ b->bank = m->bank;
+ list_add(&b->list, &banks->list);
+ }
+
+ b->status = m->status;
+ b->addr = m->addr;
+ b->misc = m->misc;
+ b->loaded = 1;

mb();
banks->loaded = 1;
@@ -45,6 +60,15 @@ static void inject_mce(struct mce *m)

static void clean_injected(struct mce_fake_banks *banks)
{
+ struct mce_fake_bank *b;
+
+ list_for_each_entry(b, &banks->list, list) {
+ /*
+ * Might be in NMI context, so avoid doing kfree here.
+ * Allocated fake bank will be reused in next injections.
+ */
+ b->loaded = 0;
+ }
banks->loaded = 0;
}

diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index edd2a82..327c72d 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -303,19 +303,26 @@ static void mce_panic(char *msg, struct mce *final, char *exp)

static u64 *mce_get_fake_reg(u32 msr)
{
- unsigned bank = __get_cpu_var(mce_fake_banks).bank;
+ struct mce_fake_bank *b;

if (msr == rip_msr)
return &__get_cpu_var(mce_fake_banks).ip;
- if (msr == MSR_IA32_MCx_STATUS(bank))
- return &__get_cpu_var(mce_fake_banks).status;
- if (msr == MSR_IA32_MCx_ADDR(bank))
- return &__get_cpu_var(mce_fake_banks).addr;
- if (msr == MSR_IA32_MCx_MISC(bank))
- return &__get_cpu_var(mce_fake_banks).misc;
if (msr == MSR_IA32_MCG_STATUS)
return &__get_cpu_var(mce_fake_banks).mcgstatus;

+ list_for_each_entry(b, &__get_cpu_var(mce_fake_banks).list, list) {
+ unsigned bank = b->bank;
+
+ if (!b->loaded)
+ continue;
+ if (msr == MSR_IA32_MCx_STATUS(bank))
+ return &b->status;
+ if (msr == MSR_IA32_MCx_ADDR(bank))
+ return &b->addr;
+ if (msr == MSR_IA32_MCx_MISC(bank))
+ return &b->misc;
+ }
+
return NULL;
}

@@ -1456,6 +1463,7 @@ void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
mce_cpu_features(c);
mce_init_timer();
INIT_WORK(&__get_cpu_var(mce_work), mce_process_work);
+ INIT_LIST_HEAD(&__get_cpu_var(mce_fake_banks).list);
}

/*
--
1.6.2.2


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/