diff options
author | Andi Kleen <ak@linux.intel.com> | 2009-04-27 12:37:43 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-05-28 12:24:12 -0400 |
commit | 06b7a7a5ec917761969444fee967c43868a76468 (patch) | |
tree | fc59ae3ccbb90d61bd7be9240a61c4bd31794cec | |
parent | 3cde5c8c839bf46a7be799ed0e1d0b4780aaf794 (diff) |
x86, mce: implement the PPro bank 0 quirk in the 64bit machine check code
Quoting the comment:
* SDM documents that on family 6 bank 0 should not be written
* because it aliases to another special BIOS controlled
* register.
* But it's not aliased anymore on model 0x1a+
* Don't ignore bank 0 completely because there could be a valid
* event later, merely don't write CTL0.
This is mostly a port on the 32bit code, except that 32bit
always didn't write it and didn't have the 0x1a heuristic. I checked
with the CPU designers that the quirk is not required starting with
this model.
Signed-off-by: Andi Kleen <ak@linux.intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index cd1313b47506..1dcd3be03328 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -65,6 +65,8 @@ static atomic_t mce_events; | |||
65 | static char trigger[128]; | 65 | static char trigger[128]; |
66 | static char *trigger_argv[2] = { trigger, NULL }; | 66 | static char *trigger_argv[2] = { trigger, NULL }; |
67 | 67 | ||
68 | static unsigned long dont_init_banks; | ||
69 | |||
68 | static DECLARE_WAIT_QUEUE_HEAD(mce_wait); | 70 | static DECLARE_WAIT_QUEUE_HEAD(mce_wait); |
69 | 71 | ||
70 | /* MCA banks polled by the period polling timer for corrected events */ | 72 | /* MCA banks polled by the period polling timer for corrected events */ |
@@ -72,6 +74,11 @@ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { | |||
72 | [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL | 74 | [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL |
73 | }; | 75 | }; |
74 | 76 | ||
77 | static inline int skip_bank_init(int i) | ||
78 | { | ||
79 | return i < BITS_PER_LONG && test_bit(i, &dont_init_banks); | ||
80 | } | ||
81 | |||
75 | /* Do initial initialization of a struct mce */ | 82 | /* Do initial initialization of a struct mce */ |
76 | void mce_setup(struct mce *m) | 83 | void mce_setup(struct mce *m) |
77 | { | 84 | { |
@@ -616,6 +623,8 @@ static void mce_init(void *dummy) | |||
616 | wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); | 623 | wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); |
617 | 624 | ||
618 | for (i = 0; i < banks; i++) { | 625 | for (i = 0; i < banks; i++) { |
626 | if (skip_bank_init(i)) | ||
627 | continue; | ||
619 | wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]); | 628 | wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]); |
620 | wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); | 629 | wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); |
621 | } | 630 | } |
@@ -643,6 +652,19 @@ static void mce_cpu_quirks(struct cpuinfo_x86 *c) | |||
643 | } | 652 | } |
644 | } | 653 | } |
645 | 654 | ||
655 | if (c->x86_vendor == X86_VENDOR_INTEL) { | ||
656 | /* | ||
657 | * SDM documents that on family 6 bank 0 should not be written | ||
658 | * because it aliases to another special BIOS controlled | ||
659 | * register. | ||
660 | * But it's not aliased anymore on model 0x1a+ | ||
661 | * Don't ignore bank 0 completely because there could be a | ||
662 | * valid event later, merely don't write CTL0. | ||
663 | */ | ||
664 | |||
665 | if (c->x86 == 6 && c->x86_model < 0x1A) | ||
666 | __set_bit(0, &dont_init_banks); | ||
667 | } | ||
646 | } | 668 | } |
647 | 669 | ||
648 | static void mce_cpu_features(struct cpuinfo_x86 *c) | 670 | static void mce_cpu_features(struct cpuinfo_x86 *c) |
@@ -911,8 +933,10 @@ static int mce_disable(void) | |||
911 | { | 933 | { |
912 | int i; | 934 | int i; |
913 | 935 | ||
914 | for (i = 0; i < banks; i++) | 936 | for (i = 0; i < banks; i++) { |
915 | wrmsrl(MSR_IA32_MC0_CTL + i*4, 0); | 937 | if (!skip_bank_init(i)) |
938 | wrmsrl(MSR_IA32_MC0_CTL + i*4, 0); | ||
939 | } | ||
916 | return 0; | 940 | return 0; |
917 | } | 941 | } |
918 | 942 | ||
@@ -1119,8 +1143,10 @@ static void mce_disable_cpu(void *h) | |||
1119 | return; | 1143 | return; |
1120 | if (!(action & CPU_TASKS_FROZEN)) | 1144 | if (!(action & CPU_TASKS_FROZEN)) |
1121 | cmci_clear(); | 1145 | cmci_clear(); |
1122 | for (i = 0; i < banks; i++) | 1146 | for (i = 0; i < banks; i++) { |
1123 | wrmsrl(MSR_IA32_MC0_CTL + i*4, 0); | 1147 | if (!skip_bank_init(i)) |
1148 | wrmsrl(MSR_IA32_MC0_CTL + i*4, 0); | ||
1149 | } | ||
1124 | } | 1150 | } |
1125 | 1151 | ||
1126 | static void mce_reenable_cpu(void *h) | 1152 | static void mce_reenable_cpu(void *h) |
@@ -1133,8 +1159,10 @@ static void mce_reenable_cpu(void *h) | |||
1133 | 1159 | ||
1134 | if (!(action & CPU_TASKS_FROZEN)) | 1160 | if (!(action & CPU_TASKS_FROZEN)) |
1135 | cmci_reenable(); | 1161 | cmci_reenable(); |
1136 | for (i = 0; i < banks; i++) | 1162 | for (i = 0; i < banks; i++) { |
1137 | wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]); | 1163 | if (!skip_bank_init(i)) |
1164 | wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]); | ||
1165 | } | ||
1138 | } | 1166 | } |
1139 | 1167 | ||
1140 | /* Get notified when a cpu comes on/off. Be hotplug friendly. */ | 1168 | /* Get notified when a cpu comes on/off. Be hotplug friendly. */ |