diff options
author | Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> | 2013-10-30 10:35:26 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2013-12-05 00:04:40 -0500 |
commit | ae744f3432d3872c51298d922728e13c24ccc068 (patch) | |
tree | 32a734e20e7cec4abf8142fc4f1ca294607162ee | |
parent | e22a22740c1ac23aaa10835f026b3549ee3e4e75 (diff) |
powerpc/book3s: Flush SLB/TLBs if we get SLB/TLB machine check errors on power8.
This patch handles the memory errors on power8. If we get a machine check
exception due to SLB or TLB errors, then flush SLBs/TLBs and reload SLBs to
recover.
Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Acked-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r-- | arch/powerpc/include/asm/mce.h | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/cputable.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/mce_power.c | 34 |
3 files changed, 41 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h index 8157d4eaead6..e3ffa825b970 100644 --- a/arch/powerpc/include/asm/mce.h +++ b/arch/powerpc/include/asm/mce.h | |||
@@ -64,4 +64,7 @@ | |||
64 | P7_DSISR_MC_SLB_MULTIHIT | \ | 64 | P7_DSISR_MC_SLB_MULTIHIT | \ |
65 | P7_DSISR_MC_SLB_MULTIHIT_PARITY) | 65 | P7_DSISR_MC_SLB_MULTIHIT_PARITY) |
66 | 66 | ||
67 | #define P8_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_SLB_ERRORS | \ | ||
68 | P8_DSISR_MC_ERAT_MULTIHIT_SEC) | ||
69 | |||
67 | #endif /* __ASM_PPC64_MCE_H__ */ | 70 | #endif /* __ASM_PPC64_MCE_H__ */ |
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index c54188bcdd9e..6c8dd5da4de5 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -74,6 +74,7 @@ extern void __restore_cpu_a2(void); | |||
74 | extern void __flush_tlb_power7(unsigned long inval_selector); | 74 | extern void __flush_tlb_power7(unsigned long inval_selector); |
75 | extern void __flush_tlb_power8(unsigned long inval_selector); | 75 | extern void __flush_tlb_power8(unsigned long inval_selector); |
76 | extern long __machine_check_early_realmode_p7(struct pt_regs *regs); | 76 | extern long __machine_check_early_realmode_p7(struct pt_regs *regs); |
77 | extern long __machine_check_early_realmode_p8(struct pt_regs *regs); | ||
77 | #endif /* CONFIG_PPC64 */ | 78 | #endif /* CONFIG_PPC64 */ |
78 | #if defined(CONFIG_E500) | 79 | #if defined(CONFIG_E500) |
79 | extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec); | 80 | extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec); |
@@ -462,6 +463,7 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
462 | .cpu_setup = __setup_cpu_power8, | 463 | .cpu_setup = __setup_cpu_power8, |
463 | .cpu_restore = __restore_cpu_power8, | 464 | .cpu_restore = __restore_cpu_power8, |
464 | .flush_tlb = __flush_tlb_power8, | 465 | .flush_tlb = __flush_tlb_power8, |
466 | .machine_check_early = __machine_check_early_realmode_p8, | ||
465 | .platform = "power8", | 467 | .platform = "power8", |
466 | }, | 468 | }, |
467 | { /* Power7 */ | 469 | { /* Power7 */ |
@@ -521,6 +523,7 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
521 | .cpu_setup = __setup_cpu_power8, | 523 | .cpu_setup = __setup_cpu_power8, |
522 | .cpu_restore = __restore_cpu_power8, | 524 | .cpu_restore = __restore_cpu_power8, |
523 | .flush_tlb = __flush_tlb_power8, | 525 | .flush_tlb = __flush_tlb_power8, |
526 | .machine_check_early = __machine_check_early_realmode_p8, | ||
524 | .platform = "power8", | 527 | .platform = "power8", |
525 | }, | 528 | }, |
526 | { /* Power8 */ | 529 | { /* Power8 */ |
@@ -540,6 +543,7 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
540 | .cpu_setup = __setup_cpu_power8, | 543 | .cpu_setup = __setup_cpu_power8, |
541 | .cpu_restore = __restore_cpu_power8, | 544 | .cpu_restore = __restore_cpu_power8, |
542 | .flush_tlb = __flush_tlb_power8, | 545 | .flush_tlb = __flush_tlb_power8, |
546 | .machine_check_early = __machine_check_early_realmode_p8, | ||
543 | .platform = "power8", | 547 | .platform = "power8", |
544 | }, | 548 | }, |
545 | { /* Cell Broadband Engine */ | 549 | { /* Cell Broadband Engine */ |
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c index 690547319b03..60a217f11275 100644 --- a/arch/powerpc/kernel/mce_power.c +++ b/arch/powerpc/kernel/mce_power.c | |||
@@ -148,3 +148,37 @@ long __machine_check_early_realmode_p7(struct pt_regs *regs) | |||
148 | /* TODO: Decode machine check reason. */ | 148 | /* TODO: Decode machine check reason. */ |
149 | return handled; | 149 | return handled; |
150 | } | 150 | } |
151 | |||
152 | static long mce_handle_ierror_p8(uint64_t srr1) | ||
153 | { | ||
154 | long handled = 0; | ||
155 | |||
156 | handled = mce_handle_common_ierror(srr1); | ||
157 | |||
158 | if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) { | ||
159 | flush_and_reload_slb(); | ||
160 | handled = 1; | ||
161 | } | ||
162 | return handled; | ||
163 | } | ||
164 | |||
165 | static long mce_handle_derror_p8(uint64_t dsisr) | ||
166 | { | ||
167 | return mce_handle_derror(dsisr, P8_DSISR_MC_SLB_ERRORS); | ||
168 | } | ||
169 | |||
170 | long __machine_check_early_realmode_p8(struct pt_regs *regs) | ||
171 | { | ||
172 | uint64_t srr1; | ||
173 | long handled = 1; | ||
174 | |||
175 | srr1 = regs->msr; | ||
176 | |||
177 | if (P7_SRR1_MC_LOADSTORE(srr1)) | ||
178 | handled = mce_handle_derror_p8(regs->dsisr); | ||
179 | else | ||
180 | handled = mce_handle_ierror_p8(srr1); | ||
181 | |||
182 | /* TODO: Decode machine check reason. */ | ||
183 | return handled; | ||
184 | } | ||