Commit 06b7a7a5 authored by Andi Kleen's avatar Andi Kleen Committed by H. Peter Anvin

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: default avatarAndi Kleen <ak@linux.intel.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
Signed-off-by: default avatarHidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
parent 3cde5c8c
...@@ -65,6 +65,8 @@ static atomic_t mce_events; ...@@ -65,6 +65,8 @@ static atomic_t mce_events;
static char trigger[128]; static char trigger[128];
static char *trigger_argv[2] = { trigger, NULL }; static char *trigger_argv[2] = { trigger, NULL };
static unsigned long dont_init_banks;
static DECLARE_WAIT_QUEUE_HEAD(mce_wait); static DECLARE_WAIT_QUEUE_HEAD(mce_wait);
/* MCA banks polled by the period polling timer for corrected events */ /* 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,6 +74,11 @@ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
[0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL [0 ... BITS_TO_LONGS(MAX_NR_BANKS)-1] = ~0UL
}; };
static inline int skip_bank_init(int i)
{
return i < BITS_PER_LONG && test_bit(i, &dont_init_banks);
}
/* Do initial initialization of a struct mce */ /* Do initial initialization of a struct mce */
void mce_setup(struct mce *m) void mce_setup(struct mce *m)
{ {
...@@ -616,6 +623,8 @@ static void mce_init(void *dummy) ...@@ -616,6 +623,8 @@ static void mce_init(void *dummy)
wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
for (i = 0; i < banks; i++) { for (i = 0; i < banks; i++) {
if (skip_bank_init(i))
continue;
wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]); wrmsrl(MSR_IA32_MC0_CTL+4*i, bank[i]);
wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0); wrmsrl(MSR_IA32_MC0_STATUS+4*i, 0);
} }
...@@ -643,6 +652,19 @@ static void mce_cpu_quirks(struct cpuinfo_x86 *c) ...@@ -643,6 +652,19 @@ static void mce_cpu_quirks(struct cpuinfo_x86 *c)
} }
} }
if (c->x86_vendor == X86_VENDOR_INTEL) {
/*
* 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.
*/
if (c->x86 == 6 && c->x86_model < 0x1A)
__set_bit(0, &dont_init_banks);
}
} }
static void mce_cpu_features(struct cpuinfo_x86 *c) static void mce_cpu_features(struct cpuinfo_x86 *c)
...@@ -911,8 +933,10 @@ static int mce_disable(void) ...@@ -911,8 +933,10 @@ static int mce_disable(void)
{ {
int i; int i;
for (i = 0; i < banks; i++) for (i = 0; i < banks; i++) {
wrmsrl(MSR_IA32_MC0_CTL + i*4, 0); if (!skip_bank_init(i))
wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
}
return 0; return 0;
} }
...@@ -1119,8 +1143,10 @@ static void mce_disable_cpu(void *h) ...@@ -1119,8 +1143,10 @@ static void mce_disable_cpu(void *h)
return; return;
if (!(action & CPU_TASKS_FROZEN)) if (!(action & CPU_TASKS_FROZEN))
cmci_clear(); cmci_clear();
for (i = 0; i < banks; i++) for (i = 0; i < banks; i++) {
wrmsrl(MSR_IA32_MC0_CTL + i*4, 0); if (!skip_bank_init(i))
wrmsrl(MSR_IA32_MC0_CTL + i*4, 0);
}
} }
static void mce_reenable_cpu(void *h) static void mce_reenable_cpu(void *h)
...@@ -1133,8 +1159,10 @@ static void mce_reenable_cpu(void *h) ...@@ -1133,8 +1159,10 @@ static void mce_reenable_cpu(void *h)
if (!(action & CPU_TASKS_FROZEN)) if (!(action & CPU_TASKS_FROZEN))
cmci_reenable(); cmci_reenable();
for (i = 0; i < banks; i++) for (i = 0; i < banks; i++) {
wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]); if (!skip_bank_init(i))
wrmsrl(MSR_IA32_MC0_CTL + i*4, bank[i]);
}
} }
/* Get notified when a cpu comes on/off. Be hotplug friendly. */ /* Get notified when a cpu comes on/off. Be hotplug friendly. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment