1 /* 2 * Machine check exception handling CPU-side for power7 and power8 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 * 18 * Copyright 2013 IBM Corporation 19 * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> 20 */ 21 22 #undef DEBUG 23 #define pr_fmt(fmt) "mce_power: " fmt 24 25 #include <linux/types.h> 26 #include <linux/ptrace.h> 27 #include <asm/mmu.h> 28 #include <asm/mce.h> 29 30 /* flush SLBs and reload */ 31 static void flush_and_reload_slb(void) 32 { 33 struct slb_shadow *slb; 34 unsigned long i, n; 35 36 /* Invalidate all SLBs */ 37 asm volatile("slbmte %0,%0; slbia" : : "r" (0)); 38 39 #ifdef CONFIG_KVM_BOOK3S_HANDLER 40 /* 41 * If machine check is hit when in guest or in transition, we will 42 * only flush the SLBs and continue. 43 */ 44 if (get_paca()->kvm_hstate.in_guest) 45 return; 46 #endif 47 48 /* For host kernel, reload the SLBs from shadow SLB buffer. */ 49 slb = get_slb_shadow(); 50 if (!slb) 51 return; 52 53 n = min_t(u32, slb->persistent, SLB_MIN_SIZE); 54 55 /* Load up the SLB entries from shadow SLB */ 56 for (i = 0; i < n; i++) { 57 unsigned long rb = slb->save_area[i].esid; 58 unsigned long rs = slb->save_area[i].vsid; 59 60 rb = (rb & ~0xFFFul) | i; 61 asm volatile("slbmte %0,%1" : : "r" (rs), "r" (rb)); 62 } 63 } 64 65 static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits) 66 { 67 long handled = 1; 68 69 /* 70 * flush and reload SLBs for SLB errors and flush TLBs for TLB errors. 71 * reset the error bits whenever we handle them so that at the end 72 * we can check whether we handled all of them or not. 73 * */ 74 if (dsisr & slb_error_bits) { 75 flush_and_reload_slb(); 76 /* reset error bits */ 77 dsisr &= ~(slb_error_bits); 78 } 79 if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { 80 if (cur_cpu_spec && cur_cpu_spec->flush_tlb) 81 cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE); 82 /* reset error bits */ 83 dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB; 84 } 85 /* Any other errors we don't understand? */ 86 if (dsisr & 0xffffffffUL) 87 handled = 0; 88 89 return handled; 90 } 91 92 static long mce_handle_derror_p7(uint64_t dsisr) 93 { 94 return mce_handle_derror(dsisr, P7_DSISR_MC_SLB_ERRORS); 95 } 96 97 static long mce_handle_common_ierror(uint64_t srr1) 98 { 99 long handled = 0; 100 101 switch (P7_SRR1_MC_IFETCH(srr1)) { 102 case 0: 103 break; 104 case P7_SRR1_MC_IFETCH_SLB_PARITY: 105 case P7_SRR1_MC_IFETCH_SLB_MULTIHIT: 106 /* flush and reload SLBs for SLB errors. */ 107 flush_and_reload_slb(); 108 handled = 1; 109 break; 110 case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: 111 if (cur_cpu_spec && cur_cpu_spec->flush_tlb) { 112 cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE); 113 handled = 1; 114 } 115 break; 116 default: 117 break; 118 } 119 120 return handled; 121 } 122 123 static long mce_handle_ierror_p7(uint64_t srr1) 124 { 125 long handled = 0; 126 127 handled = mce_handle_common_ierror(srr1); 128 129 if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) { 130 flush_and_reload_slb(); 131 handled = 1; 132 } 133 return handled; 134 } 135 136 long __machine_check_early_realmode_p7(struct pt_regs *regs) 137 { 138 uint64_t srr1; 139 long handled = 1; 140 141 srr1 = regs->msr; 142 143 if (P7_SRR1_MC_LOADSTORE(srr1)) 144 handled = mce_handle_derror_p7(regs->dsisr); 145 else 146 handled = mce_handle_ierror_p7(srr1); 147 148 /* TODO: Decode machine check reason. */ 149 return handled; 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 } 185