diff -r 46b874d60375 xen/arch/x86/cpu/mcheck/Makefile --- a/xen/arch/x86/cpu/mcheck/Makefile Fri Aug 14 12:26:35 2009 +0100 +++ b/xen/arch/x86/cpu/mcheck/Makefile Fri Aug 14 16:46:42 2009 +0200 @@ -5,4 +5,5 @@ obj-y += amd_f10.o obj-y += mctelem.o obj-y += mce.o obj-y += mce_intel.o +obj-y += mce_amd_quirks.o obj-y += non-fatal.o diff -r 46b874d60375 xen/arch/x86/cpu/mcheck/amd_k8.c --- a/xen/arch/x86/cpu/mcheck/amd_k8.c Fri Aug 14 12:26:35 2009 +0100 +++ b/xen/arch/x86/cpu/mcheck/amd_k8.c Fri Aug 14 16:46:42 2009 +0200 @@ -67,7 +67,7 @@ #include #include "mce.h" - +#include "mce_quirks.h" /* Machine Check Handler for AMD K8 family series */ static void k8_machine_check(struct cpu_user_regs *regs, long error_code) @@ -79,31 +79,21 @@ static void k8_machine_check(struct cpu_ int amd_k8_mcheck_init(struct cpuinfo_x86 *c) { uint32_t i; + enum mcequirk_amd_flags quirkflag; /* Check for PPro style MCA; our caller has confirmed MCE support. */ if (!cpu_has(c, X86_FEATURE_MCA)) return 0; + quirkflag = mcequirk_lookup_amd_quirkdata(c); + mce_cap_init(); x86_mce_vector_register(k8_machine_check); for (i = 0; i < nr_mce_banks; i++) { - switch (i) { - case 4: /* Northbridge */ - if (c->x86 == 0xf) { - /* - * Enable error reporting of all errors except - * for GART TBL walk error reporting, which - * trips off incorrectly with IOMMU & 3ware & - * Cerberus. - */ - wrmsrl(MSR_IA32_MC4_CTL, ~(1ULL << 10)); - wrmsrl(MSR_IA32_MC4_STATUS, 0x0ULL); - break; - } - /* fall through */ - - default: + if (quirkflag == MCEQUIRK_K8_GART && i == 4) { + mcequirk_amd_apply(quirkflag); + } else { /* Enable error reporting of all errors */ wrmsrl(MSR_IA32_MC0_CTL + 4 * i, 0xffffffffffffffffULL); wrmsrl(MSR_IA32_MC0_STATUS + 4 * i, 0x0ULL); diff -r 46b874d60375 xen/arch/x86/cpu/mcheck/mce_amd_quirks.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/cpu/mcheck/mce_amd_quirks.c Fri Aug 14 16:46:42 2009 +0200 @@ -0,0 +1,73 @@ +/* + * MCA quirks for AMD CPUs + * Copyright (c) 2009 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include "mce_quirks.h" + +#define ANY -1 + +static const struct mce_quirkdata mce_amd_quirks[] = { + { 0x6 /* cpu family */, ANY /* all models */, ANY /* all steppings */, + MCEQUIRK_K7_BANK0 }, + { 0xf /* cpu family */, ANY /* all models */, ANY /* all steppings */, + MCEQUIRK_K8_GART }, +}; + +enum mcequirk_amd_flags +mcequirk_lookup_amd_quirkdata(struct cpuinfo_x86 *c) +{ + int i; + + BUG_ON(c->x86_vendor != X86_VENDOR_AMD); + + for (i = 0; i < ARRAY_SIZE(mce_amd_quirks); i++) { + if (c->x86 != mce_amd_quirks[i].cpu_family) + continue; + if ( (mce_amd_quirks[i].cpu_model != ANY) && + (mce_amd_quirks[i].cpu_model != c->x86_model) ) + continue; + if ( (mce_amd_quirks[i].cpu_stepping != ANY) && + (mce_amd_quirks[i].cpu_stepping != c->x86_mask) ) + continue; + return mce_amd_quirks[i].quirk; + } + return 0; +} + +int mcequirk_amd_apply(enum mcequirk_amd_flags flags) +{ + switch (flags) { + case MCEQUIRK_K7_BANK0: + return 1; /* first bank */ + + case MCEQUIRK_K8_GART: + /* + * Enable error reporting for all errors except for GART + * TBL walk error reporting, which trips off incorrectly + * with AGP GART & 3ware & Cerberus. + */ + wrmsrl(MSR_IA32_MC4_CTL, ~(1ULL << 10)); + wrmsrl(MSR_IA32_MC4_STATUS, 0ULL); + break; + } + + return 0; +} diff -r 46b874d60375 xen/arch/x86/cpu/mcheck/mce_quirks.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/cpu/mcheck/mce_quirks.h Fri Aug 14 16:46:42 2009 +0200 @@ -0,0 +1,54 @@ +/* * MCA quirks + * Copyright (c) 2009 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _MCE_QUIRK_H +#define _MCE_QUIRK_H + +#include + +struct mce_quirkdata { + int32_t cpu_family; + int16_t cpu_model; + int16_t cpu_stepping; + uint32_t quirk; +}; + +/* use a binary flag if multiple quirks apply + * to one CPU family/model + */ + +enum mcequirk_amd_flags { + MCEQUIRK_K7_BANK0 = 0x1, + MCEQUIRK_K8_GART = 0x2, +}; + +enum mcequirk_intel_flags { + MCEQUIRK_DUMMY = 0x1, /* nothing known yet */ +}; + +enum mcequirk_amd_flags +mcequirk_lookup_amd_quirkdata(struct cpuinfo_x86 *c); + +int mcequirk_amd_apply(enum mcequirk_amd_flags flags); + +enum mcequirk_intel_flags +mcequirk_lookup_intel_quirkdata(struct cpuinfo_x86 *c); + +int mcequirk_intel_apply(enum mcequirk_intel_flags flags); + +#endif /* _MCE_QUIRK_H */