powerpc/book3s: Flush SLB/TLBs if we get SLB/TLB machine check errors on power8.
authorMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Wed, 30 Oct 2013 14:35:26 +0000 (20:05 +0530)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 5 Dec 2013 05:04:40 +0000 (16:04 +1100)
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>
arch/powerpc/include/asm/mce.h
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/mce_power.c

index 8157d4e..e3ffa82 100644 (file)
@@ -64,4 +64,7 @@
                                         P7_DSISR_MC_SLB_MULTIHIT | \
                                         P7_DSISR_MC_SLB_MULTIHIT_PARITY)
 
+#define P8_DSISR_MC_SLB_ERRORS         (P7_DSISR_MC_SLB_ERRORS | \
+                                        P8_DSISR_MC_ERAT_MULTIHIT_SEC)
+
 #endif /* __ASM_PPC64_MCE_H__ */
index c54188b..6c8dd5d 100644 (file)
@@ -74,6 +74,7 @@ extern void __restore_cpu_a2(void);
 extern void __flush_tlb_power7(unsigned long inval_selector);
 extern void __flush_tlb_power8(unsigned long inval_selector);
 extern long __machine_check_early_realmode_p7(struct pt_regs *regs);
+extern long __machine_check_early_realmode_p8(struct pt_regs *regs);
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_E500)
 extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
@@ -462,6 +463,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_setup              = __setup_cpu_power8,
                .cpu_restore            = __restore_cpu_power8,
                .flush_tlb              = __flush_tlb_power8,
+               .machine_check_early    = __machine_check_early_realmode_p8,
                .platform               = "power8",
        },
        {       /* Power7 */
@@ -521,6 +523,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_setup              = __setup_cpu_power8,
                .cpu_restore            = __restore_cpu_power8,
                .flush_tlb              = __flush_tlb_power8,
+               .machine_check_early    = __machine_check_early_realmode_p8,
                .platform               = "power8",
        },
        {       /* Power8 */
@@ -540,6 +543,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .cpu_setup              = __setup_cpu_power8,
                .cpu_restore            = __restore_cpu_power8,
                .flush_tlb              = __flush_tlb_power8,
+               .machine_check_early    = __machine_check_early_realmode_p8,
                .platform               = "power8",
        },
        {       /* Cell Broadband Engine */
index 6905473..60a217f 100644 (file)
@@ -148,3 +148,37 @@ long __machine_check_early_realmode_p7(struct pt_regs *regs)
        /* TODO: Decode machine check reason. */
        return handled;
 }
+
+static long mce_handle_ierror_p8(uint64_t srr1)
+{
+       long handled = 0;
+
+       handled = mce_handle_common_ierror(srr1);
+
+       if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) {
+               flush_and_reload_slb();
+               handled = 1;
+       }
+       return handled;
+}
+
+static long mce_handle_derror_p8(uint64_t dsisr)
+{
+       return mce_handle_derror(dsisr, P8_DSISR_MC_SLB_ERRORS);
+}
+
+long __machine_check_early_realmode_p8(struct pt_regs *regs)
+{
+       uint64_t srr1;
+       long handled = 1;
+
+       srr1 = regs->msr;
+
+       if (P7_SRR1_MC_LOADSTORE(srr1))
+               handled = mce_handle_derror_p8(regs->dsisr);
+       else
+               handled = mce_handle_ierror_p8(srr1);
+
+       /* TODO: Decode machine check reason. */
+       return handled;
+}