Messages in this thread Patch in this message |  | | | Date | Fri, 09 Oct 2009 14:46:47 +0900 | | From | Hidetoshi Seto <> | | Subject | [PATCH 4/4] mce-inject: support injecting multiple error to a CPU |
| |
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@jp.fujitsu.com> --- 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
|  |