Commit 89b831ef authored by Jacob Shin's avatar Jacob Shin Committed by Linus Torvalds

[PATCH] x86_64: Support for AMD specific MCE Threshold.

MC4_MISC - DRAM Errors Threshold Register realized under AMD K8 Rev F.
This register is used to count correctable and uncorrectable ECC errors that occur during DRAM read operations.
The user may interface through sysfs files in order to change the threshold configuration.

bank%d/error_count - reads current error count, write to clear.
bank%d/interrupt_enable - set/clear interrupt enable.
bank%d/threshold_limit - read/write the threshold limit.

APIC vector 0xF9 in hw_irq.h.
5 software defined bank ids in mce.h.
new apic.c function to setup threshold apic lvt.
defaults to interrupt off, count enabled, and threshold limit max.
sysfs interface created on /sys/devices/system/threshold.

AK: added some ifdefs to make it compile on UP
Signed-off-by: default avatarJacob Shin <jacob.shin@amd.com>
Signed-off-by: default avatarAndi Kleen <ak@suse.de>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 979edfad
...@@ -374,6 +374,14 @@ config X86_MCE_INTEL ...@@ -374,6 +374,14 @@ config X86_MCE_INTEL
Additional support for intel specific MCE features such as Additional support for intel specific MCE features such as
the thermal monitor. the thermal monitor.
config X86_MCE_AMD
bool "AMD MCE features"
depends on X86_MCE && X86_LOCAL_APIC
default y
help
Additional support for AMD specific MCE features such as
the DRAM Error Threshold.
config PHYSICAL_START config PHYSICAL_START
hex "Physical address where the kernel is loaded" if EMBEDDED hex "Physical address where the kernel is loaded" if EMBEDDED
default "0x100000" default "0x100000"
......
...@@ -11,6 +11,7 @@ obj-y := process.o signal.o entry.o traps.o irq.o \ ...@@ -11,6 +11,7 @@ obj-y := process.o signal.o entry.o traps.o irq.o \
obj-$(CONFIG_X86_MCE) += mce.o obj-$(CONFIG_X86_MCE) += mce.o
obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o obj-$(CONFIG_X86_MCE_INTEL) += mce_intel.o
obj-$(CONFIG_X86_MCE_AMD) += mce_amd.o
obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/ obj-$(CONFIG_MTRR) += ../../i386/kernel/cpu/mtrr/
obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_ACPI) += acpi/
obj-$(CONFIG_X86_MSR) += msr.o obj-$(CONFIG_X86_MSR) += msr.o
......
...@@ -833,6 +833,16 @@ int setup_profiling_timer(unsigned int multiplier) ...@@ -833,6 +833,16 @@ int setup_profiling_timer(unsigned int multiplier)
return 0; return 0;
} }
#ifdef CONFIG_X86_MCE_AMD
void setup_threshold_lvt(unsigned long lvt_off)
{
unsigned int v = 0;
unsigned long reg = (lvt_off << 4) + 0x500;
v |= THRESHOLD_APIC_VECTOR;
apic_write(reg, v);
}
#endif /* CONFIG_X86_MCE_AMD */
#undef APIC_DIVISOR #undef APIC_DIVISOR
/* /*
......
...@@ -612,6 +612,9 @@ retint_kernel: ...@@ -612,6 +612,9 @@ retint_kernel:
ENTRY(thermal_interrupt) ENTRY(thermal_interrupt)
apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
ENTRY(threshold_interrupt)
apicinterrupt THRESHOLD_APIC_VECTOR,mce_threshold_interrupt
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
ENTRY(reschedule_interrupt) ENTRY(reschedule_interrupt)
apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt apicinterrupt RESCHEDULE_VECTOR,smp_reschedule_interrupt
......
...@@ -492,6 +492,7 @@ void invalidate_interrupt5(void); ...@@ -492,6 +492,7 @@ void invalidate_interrupt5(void);
void invalidate_interrupt6(void); void invalidate_interrupt6(void);
void invalidate_interrupt7(void); void invalidate_interrupt7(void);
void thermal_interrupt(void); void thermal_interrupt(void);
void threshold_interrupt(void);
void i8254_timer_resume(void); void i8254_timer_resume(void);
static void setup_timer_hardware(void) static void setup_timer_hardware(void)
...@@ -580,6 +581,7 @@ void __init init_IRQ(void) ...@@ -580,6 +581,7 @@ void __init init_IRQ(void)
set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt); set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
#endif #endif
set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt); set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
set_intr_gate(THRESHOLD_APIC_VECTOR, threshold_interrupt);
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
/* self generated IPI for local APIC timer */ /* self generated IPI for local APIC timer */
......
...@@ -356,6 +356,9 @@ static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c) ...@@ -356,6 +356,9 @@ static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
case X86_VENDOR_INTEL: case X86_VENDOR_INTEL:
mce_intel_feature_init(c); mce_intel_feature_init(c);
break; break;
case X86_VENDOR_AMD:
mce_amd_feature_init(c);
break;
default: default:
break; break;
} }
......
This diff is collapsed.
...@@ -888,6 +888,10 @@ asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) ...@@ -888,6 +888,10 @@ asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
{ {
} }
asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void)
{
}
/* /*
* 'math_state_restore()' saves the current math information in the * 'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task * old math state array, and gets the new ones from the current task
......
...@@ -111,6 +111,8 @@ extern unsigned int nmi_watchdog; ...@@ -111,6 +111,8 @@ extern unsigned int nmi_watchdog;
extern int disable_timer_pin_1; extern int disable_timer_pin_1;
extern void setup_threshold_lvt(unsigned long lvt_off);
#endif /* CONFIG_X86_LOCAL_APIC */ #endif /* CONFIG_X86_LOCAL_APIC */
extern unsigned boot_cpu_id; extern unsigned boot_cpu_id;
......
...@@ -55,7 +55,7 @@ struct hw_interrupt_type; ...@@ -55,7 +55,7 @@ struct hw_interrupt_type;
#define CALL_FUNCTION_VECTOR 0xfc #define CALL_FUNCTION_VECTOR 0xfc
#define KDB_VECTOR 0xfb /* reserved for KDB */ #define KDB_VECTOR 0xfb /* reserved for KDB */
#define THERMAL_APIC_VECTOR 0xfa #define THERMAL_APIC_VECTOR 0xfa
/* 0xf9 free */ #define THRESHOLD_APIC_VECTOR 0xf9
#define INVALIDATE_TLB_VECTOR_END 0xf8 #define INVALIDATE_TLB_VECTOR_END 0xf8
#define INVALIDATE_TLB_VECTOR_START 0xf0 /* f0-f8 used for TLB flush */ #define INVALIDATE_TLB_VECTOR_START 0xf0 /* f0-f8 used for TLB flush */
......
...@@ -67,6 +67,8 @@ struct mce_log { ...@@ -67,6 +67,8 @@ struct mce_log {
/* Software defined banks */ /* Software defined banks */
#define MCE_EXTENDED_BANK 128 #define MCE_EXTENDED_BANK 128
#define MCE_THERMAL_BANK MCE_EXTENDED_BANK + 0 #define MCE_THERMAL_BANK MCE_EXTENDED_BANK + 0
#define MCE_THRESHOLD_BASE MCE_EXTENDED_BANK + 1 /* MCE_AMD */
#define MCE_THRESHOLD_DRAM_ECC MCE_THRESHOLD_BASE + 4
void mce_log(struct mce *m); void mce_log(struct mce *m);
#ifdef CONFIG_X86_MCE_INTEL #ifdef CONFIG_X86_MCE_INTEL
...@@ -77,4 +79,12 @@ static inline void mce_intel_feature_init(struct cpuinfo_x86 *c) ...@@ -77,4 +79,12 @@ static inline void mce_intel_feature_init(struct cpuinfo_x86 *c)
} }
#endif #endif
#ifdef CONFIG_X86_MCE_AMD
void mce_amd_feature_init(struct cpuinfo_x86 *c);
#else
static inline void mce_amd_feature_init(struct cpuinfo_x86 *c)
{
}
#endif
#endif #endif
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