diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-10-08 15:06:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-10-08 15:06:36 -0400 |
commit | 624235c5b3a62639136b7823c2c88e4aeb5c5a8d (patch) | |
tree | 563cedd7577458a3c849549b84729beeca84da0c | |
parent | f17f36bb1c006818441b84cf65a6decf3e59942b (diff) | |
parent | e3be785fb59f92c0df685037062d041619653b7a (diff) |
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
x86, pci: Correct spelling in a comment
x86: Simplify bound checks in the MTRR code
x86: EDAC: carve out AMD MCE decoding logic
initcalls: Add early_initcall() for modules
x86: EDAC: MCE: Fix MCE decoding callback logic
-rw-r--r-- | arch/x86/include/asm/mce.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce.c | 58 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/if.c | 17 | ||||
-rw-r--r-- | arch/x86/kernel/pci-dma.c | 2 | ||||
-rw-r--r-- | drivers/edac/Kconfig | 14 | ||||
-rw-r--r-- | drivers/edac/Makefile | 5 | ||||
-rw-r--r-- | drivers/edac/edac_mce_amd.c | 32 | ||||
-rw-r--r-- | include/linux/init.h | 1 |
8 files changed, 97 insertions, 34 deletions
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index b608a64c5814..f1363b72364f 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h | |||
@@ -133,6 +133,8 @@ static inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {} | |||
133 | static inline void enable_p5_mce(void) {} | 133 | static inline void enable_p5_mce(void) {} |
134 | #endif | 134 | #endif |
135 | 135 | ||
136 | extern void (*x86_mce_decode_callback)(struct mce *m); | ||
137 | |||
136 | void mce_setup(struct mce *m); | 138 | void mce_setup(struct mce *m); |
137 | void mce_log(struct mce *m); | 139 | void mce_log(struct mce *m); |
138 | DECLARE_PER_CPU(struct sys_device, mce_dev); | 140 | DECLARE_PER_CPU(struct sys_device, mce_dev); |
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 183c3457d2f4..b1598a9436d0 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c | |||
@@ -85,6 +85,18 @@ static DECLARE_WAIT_QUEUE_HEAD(mce_wait); | |||
85 | static DEFINE_PER_CPU(struct mce, mces_seen); | 85 | static DEFINE_PER_CPU(struct mce, mces_seen); |
86 | static int cpu_missing; | 86 | static int cpu_missing; |
87 | 87 | ||
88 | static void default_decode_mce(struct mce *m) | ||
89 | { | ||
90 | pr_emerg("No human readable MCE decoding support on this CPU type.\n"); | ||
91 | pr_emerg("Run the message through 'mcelog --ascii' to decode.\n"); | ||
92 | } | ||
93 | |||
94 | /* | ||
95 | * CPU/chipset specific EDAC code can register a callback here to print | ||
96 | * MCE errors in a human-readable form: | ||
97 | */ | ||
98 | void (*x86_mce_decode_callback)(struct mce *m) = default_decode_mce; | ||
99 | EXPORT_SYMBOL(x86_mce_decode_callback); | ||
88 | 100 | ||
89 | /* MCA banks polled by the period polling timer for corrected events */ | 101 | /* MCA banks polled by the period polling timer for corrected events */ |
90 | DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { | 102 | DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = { |
@@ -165,46 +177,46 @@ void mce_log(struct mce *mce) | |||
165 | set_bit(0, &mce_need_notify); | 177 | set_bit(0, &mce_need_notify); |
166 | } | 178 | } |
167 | 179 | ||
168 | void __weak decode_mce(struct mce *m) | ||
169 | { | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | static void print_mce(struct mce *m) | 180 | static void print_mce(struct mce *m) |
174 | { | 181 | { |
175 | printk(KERN_EMERG | 182 | pr_emerg("CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n", |
176 | "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n", | ||
177 | m->extcpu, m->mcgstatus, m->bank, m->status); | 183 | m->extcpu, m->mcgstatus, m->bank, m->status); |
184 | |||
178 | if (m->ip) { | 185 | if (m->ip) { |
179 | printk(KERN_EMERG "RIP%s %02x:<%016Lx> ", | 186 | pr_emerg("RIP%s %02x:<%016Lx> ", |
180 | !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "", | 187 | !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "", |
181 | m->cs, m->ip); | 188 | m->cs, m->ip); |
189 | |||
182 | if (m->cs == __KERNEL_CS) | 190 | if (m->cs == __KERNEL_CS) |
183 | print_symbol("{%s}", m->ip); | 191 | print_symbol("{%s}", m->ip); |
184 | printk(KERN_CONT "\n"); | 192 | pr_cont("\n"); |
185 | } | 193 | } |
186 | printk(KERN_EMERG "TSC %llx ", m->tsc); | 194 | |
195 | pr_emerg("TSC %llx ", m->tsc); | ||
187 | if (m->addr) | 196 | if (m->addr) |
188 | printk(KERN_CONT "ADDR %llx ", m->addr); | 197 | pr_cont("ADDR %llx ", m->addr); |
189 | if (m->misc) | 198 | if (m->misc) |
190 | printk(KERN_CONT "MISC %llx ", m->misc); | 199 | pr_cont("MISC %llx ", m->misc); |
191 | printk(KERN_CONT "\n"); | 200 | |
192 | printk(KERN_EMERG "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n", | 201 | pr_cont("\n"); |
193 | m->cpuvendor, m->cpuid, m->time, m->socketid, | 202 | pr_emerg("PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n", |
194 | m->apicid); | 203 | m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid); |
195 | 204 | ||
196 | decode_mce(m); | 205 | /* |
206 | * Print out human-readable details about the MCE error, | ||
207 | * (if the CPU has an implementation for that): | ||
208 | */ | ||
209 | x86_mce_decode_callback(m); | ||
197 | } | 210 | } |
198 | 211 | ||
199 | static void print_mce_head(void) | 212 | static void print_mce_head(void) |
200 | { | 213 | { |
201 | printk(KERN_EMERG "\nHARDWARE ERROR\n"); | 214 | pr_emerg("\nHARDWARE ERROR\n"); |
202 | } | 215 | } |
203 | 216 | ||
204 | static void print_mce_tail(void) | 217 | static void print_mce_tail(void) |
205 | { | 218 | { |
206 | printk(KERN_EMERG "This is not a software problem!\n" | 219 | pr_emerg("This is not a software problem!\n"); |
207 | "Run through mcelog --ascii to decode and contact your hardware vendor\n"); | ||
208 | } | 220 | } |
209 | 221 | ||
210 | #define PANIC_TIMEOUT 5 /* 5 seconds */ | 222 | #define PANIC_TIMEOUT 5 /* 5 seconds */ |
@@ -218,6 +230,7 @@ static atomic_t mce_fake_paniced; | |||
218 | static void wait_for_panic(void) | 230 | static void wait_for_panic(void) |
219 | { | 231 | { |
220 | long timeout = PANIC_TIMEOUT*USEC_PER_SEC; | 232 | long timeout = PANIC_TIMEOUT*USEC_PER_SEC; |
233 | |||
221 | preempt_disable(); | 234 | preempt_disable(); |
222 | local_irq_enable(); | 235 | local_irq_enable(); |
223 | while (timeout-- > 0) | 236 | while (timeout-- > 0) |
@@ -285,6 +298,7 @@ static void mce_panic(char *msg, struct mce *final, char *exp) | |||
285 | static int msr_to_offset(u32 msr) | 298 | static int msr_to_offset(u32 msr) |
286 | { | 299 | { |
287 | unsigned bank = __get_cpu_var(injectm.bank); | 300 | unsigned bank = __get_cpu_var(injectm.bank); |
301 | |||
288 | if (msr == rip_msr) | 302 | if (msr == rip_msr) |
289 | return offsetof(struct mce, ip); | 303 | return offsetof(struct mce, ip); |
290 | if (msr == MSR_IA32_MCx_STATUS(bank)) | 304 | if (msr == MSR_IA32_MCx_STATUS(bank)) |
diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c index f04e72527604..3c1b12d461d1 100644 --- a/arch/x86/kernel/cpu/mtrr/if.c +++ b/arch/x86/kernel/cpu/mtrr/if.c | |||
@@ -96,17 +96,24 @@ mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos) | |||
96 | unsigned long long base, size; | 96 | unsigned long long base, size; |
97 | char *ptr; | 97 | char *ptr; |
98 | char line[LINE_SIZE]; | 98 | char line[LINE_SIZE]; |
99 | int length; | ||
99 | size_t linelen; | 100 | size_t linelen; |
100 | 101 | ||
101 | if (!capable(CAP_SYS_ADMIN)) | 102 | if (!capable(CAP_SYS_ADMIN)) |
102 | return -EPERM; | 103 | return -EPERM; |
103 | if (!len) | ||
104 | return -EINVAL; | ||
105 | 104 | ||
106 | memset(line, 0, LINE_SIZE); | 105 | memset(line, 0, LINE_SIZE); |
107 | if (len > LINE_SIZE) | 106 | |
108 | len = LINE_SIZE; | 107 | length = len; |
109 | if (copy_from_user(line, buf, len - 1)) | 108 | length--; |
109 | |||
110 | if (length > LINE_SIZE - 1) | ||
111 | length = LINE_SIZE - 1; | ||
112 | |||
113 | if (length < 0) | ||
114 | return -EINVAL; | ||
115 | |||
116 | if (copy_from_user(line, buf, length)) | ||
110 | return -EFAULT; | 117 | return -EFAULT; |
111 | 118 | ||
112 | linelen = strlen(line); | 119 | linelen = strlen(line); |
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 64b838eac18c..d20009b4e6ef 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c | |||
@@ -35,7 +35,7 @@ int iommu_detected __read_mostly = 0; | |||
35 | 35 | ||
36 | /* | 36 | /* |
37 | * This variable becomes 1 if iommu=pt is passed on the kernel command line. | 37 | * This variable becomes 1 if iommu=pt is passed on the kernel command line. |
38 | * If this variable is 1, IOMMU implementations do no DMA ranslation for | 38 | * If this variable is 1, IOMMU implementations do no DMA translation for |
39 | * devices and allow every device to access to whole physical memory. This is | 39 | * devices and allow every device to access to whole physical memory. This is |
40 | * useful if a user want to use an IOMMU only for KVM device assignment to | 40 | * useful if a user want to use an IOMMU only for KVM device assignment to |
41 | * guests and not for driver dma translation. | 41 | * guests and not for driver dma translation. |
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 02127e59fe8e..55c9c59b3f71 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
@@ -47,6 +47,18 @@ config EDAC_DEBUG_VERBOSE | |||
47 | Source file name and line number where debugging message | 47 | Source file name and line number where debugging message |
48 | printed will be added to debugging message. | 48 | printed will be added to debugging message. |
49 | 49 | ||
50 | config EDAC_DECODE_MCE | ||
51 | tristate "Decode MCEs in human-readable form (only on AMD for now)" | ||
52 | depends on CPU_SUP_AMD && X86_MCE | ||
53 | default y | ||
54 | ---help--- | ||
55 | Enable this option if you want to decode Machine Check Exceptions | ||
56 | occuring on your machine in human-readable form. | ||
57 | |||
58 | You should definitely say Y here in case you want to decode MCEs | ||
59 | which occur really early upon boot, before the module infrastructure | ||
60 | has been initialized. | ||
61 | |||
50 | config EDAC_MM_EDAC | 62 | config EDAC_MM_EDAC |
51 | tristate "Main Memory EDAC (Error Detection And Correction) reporting" | 63 | tristate "Main Memory EDAC (Error Detection And Correction) reporting" |
52 | help | 64 | help |
@@ -59,7 +71,7 @@ config EDAC_MM_EDAC | |||
59 | 71 | ||
60 | config EDAC_AMD64 | 72 | config EDAC_AMD64 |
61 | tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h" | 73 | tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h" |
62 | depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && CPU_SUP_AMD | 74 | depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE |
63 | help | 75 | help |
64 | Support for error detection and correction on the AMD 64 | 76 | Support for error detection and correction on the AMD 64 |
65 | Families of Memory Controllers (K8, F10h and F11h) | 77 | Families of Memory Controllers (K8, F10h and F11h) |
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 7a473bbe8abd..bc5dc232a0fb 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile | |||
@@ -6,7 +6,6 @@ | |||
6 | # GNU General Public License. | 6 | # GNU General Public License. |
7 | # | 7 | # |
8 | 8 | ||
9 | |||
10 | obj-$(CONFIG_EDAC) := edac_stub.o | 9 | obj-$(CONFIG_EDAC) := edac_stub.o |
11 | obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o | 10 | obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o |
12 | 11 | ||
@@ -17,9 +16,7 @@ ifdef CONFIG_PCI | |||
17 | edac_core-objs += edac_pci.o edac_pci_sysfs.o | 16 | edac_core-objs += edac_pci.o edac_pci_sysfs.o |
18 | endif | 17 | endif |
19 | 18 | ||
20 | ifdef CONFIG_CPU_SUP_AMD | 19 | obj-$(CONFIG_EDAC_DECODE_MCE) += edac_mce_amd.o |
21 | edac_core-objs += edac_mce_amd.o | ||
22 | endif | ||
23 | 20 | ||
24 | obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o | 21 | obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o |
25 | obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o | 22 | obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o |
diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c index 0c21c370c9dd..713ed7d37247 100644 --- a/drivers/edac/edac_mce_amd.c +++ b/drivers/edac/edac_mce_amd.c | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | static bool report_gart_errors; | 4 | static bool report_gart_errors; |
5 | static void (*nb_bus_decoder)(int node_id, struct err_regs *regs); | 5 | static void (*nb_bus_decoder)(int node_id, struct err_regs *regs); |
6 | static void (*orig_mce_callback)(struct mce *m); | ||
6 | 7 | ||
7 | void amd_report_gart_errors(bool v) | 8 | void amd_report_gart_errors(bool v) |
8 | { | 9 | { |
@@ -362,7 +363,7 @@ static inline void amd_decode_err_code(unsigned int ec) | |||
362 | pr_warning("Huh? Unknown MCE error 0x%x\n", ec); | 363 | pr_warning("Huh? Unknown MCE error 0x%x\n", ec); |
363 | } | 364 | } |
364 | 365 | ||
365 | void decode_mce(struct mce *m) | 366 | static void amd_decode_mce(struct mce *m) |
366 | { | 367 | { |
367 | struct err_regs regs; | 368 | struct err_regs regs; |
368 | int node, ecc; | 369 | int node, ecc; |
@@ -420,3 +421,32 @@ void decode_mce(struct mce *m) | |||
420 | 421 | ||
421 | amd_decode_err_code(m->status & 0xffff); | 422 | amd_decode_err_code(m->status & 0xffff); |
422 | } | 423 | } |
424 | |||
425 | static int __init mce_amd_init(void) | ||
426 | { | ||
427 | /* | ||
428 | * We can decode MCEs for Opteron and later CPUs: | ||
429 | */ | ||
430 | if ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && | ||
431 | (boot_cpu_data.x86 >= 0xf)) { | ||
432 | /* safe the default decode mce callback */ | ||
433 | orig_mce_callback = x86_mce_decode_callback; | ||
434 | |||
435 | x86_mce_decode_callback = amd_decode_mce; | ||
436 | } | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | early_initcall(mce_amd_init); | ||
441 | |||
442 | #ifdef MODULE | ||
443 | static void __exit mce_amd_exit(void) | ||
444 | { | ||
445 | x86_mce_decode_callback = orig_mce_callback; | ||
446 | } | ||
447 | |||
448 | MODULE_DESCRIPTION("AMD MCE decoder"); | ||
449 | MODULE_ALIAS("edac-mce-amd"); | ||
450 | MODULE_LICENSE("GPL"); | ||
451 | module_exit(mce_amd_exit); | ||
452 | #endif | ||
diff --git a/include/linux/init.h b/include/linux/init.h index 400adbb45414..ff8bde520d03 100644 --- a/include/linux/init.h +++ b/include/linux/init.h | |||
@@ -271,6 +271,7 @@ void __init parse_early_options(char *cmdline); | |||
271 | #else /* MODULE */ | 271 | #else /* MODULE */ |
272 | 272 | ||
273 | /* Don't use these in modules, but some people do... */ | 273 | /* Don't use these in modules, but some people do... */ |
274 | #define early_initcall(fn) module_init(fn) | ||
274 | #define core_initcall(fn) module_init(fn) | 275 | #define core_initcall(fn) module_init(fn) |
275 | #define postcore_initcall(fn) module_init(fn) | 276 | #define postcore_initcall(fn) module_init(fn) |
276 | #define arch_initcall(fn) module_init(fn) | 277 | #define arch_initcall(fn) module_init(fn) |