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 static void mce_get_common_ierror(struct mce_error_info *mce_err, uint64_t srr1) 137 { 138 switch (P7_SRR1_MC_IFETCH(srr1)) { 139 case P7_SRR1_MC_IFETCH_SLB_PARITY: 140 mce_err->error_type = MCE_ERROR_TYPE_SLB; 141 mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY; 142 break; 143 case P7_SRR1_MC_IFETCH_SLB_MULTIHIT: 144 mce_err->error_type = MCE_ERROR_TYPE_SLB; 145 mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT; 146 break; 147 case P7_SRR1_MC_IFETCH_TLB_MULTIHIT: 148 mce_err->error_type = MCE_ERROR_TYPE_TLB; 149 mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT; 150 break; 151 case P7_SRR1_MC_IFETCH_UE: 152 case P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL: 153 mce_err->error_type = MCE_ERROR_TYPE_UE; 154 mce_err->u.ue_error_type = MCE_UE_ERROR_IFETCH; 155 break; 156 case P7_SRR1_MC_IFETCH_UE_TLB_RELOAD: 157 mce_err->error_type = MCE_ERROR_TYPE_UE; 158 mce_err->u.ue_error_type = 159 MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH; 160 break; 161 } 162 } 163 164 static void mce_get_ierror_p7(struct mce_error_info *mce_err, uint64_t srr1) 165 { 166 mce_get_common_ierror(mce_err, srr1); 167 if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) { 168 mce_err->error_type = MCE_ERROR_TYPE_SLB; 169 mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE; 170 } 171 } 172 173 static void mce_get_derror_p7(struct mce_error_info *mce_err, uint64_t dsisr) 174 { 175 if (dsisr & P7_DSISR_MC_UE) { 176 mce_err->error_type = MCE_ERROR_TYPE_UE; 177 mce_err->u.ue_error_type = MCE_UE_ERROR_LOAD_STORE; 178 } else if (dsisr & P7_DSISR_MC_UE_TABLEWALK) { 179 mce_err->error_type = MCE_ERROR_TYPE_UE; 180 mce_err->u.ue_error_type = 181 MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE; 182 } else if (dsisr & P7_DSISR_MC_ERAT_MULTIHIT) { 183 mce_err->error_type = MCE_ERROR_TYPE_ERAT; 184 mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; 185 } else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT) { 186 mce_err->error_type = MCE_ERROR_TYPE_SLB; 187 mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT; 188 } else if (dsisr & P7_DSISR_MC_SLB_PARITY_MFSLB) { 189 mce_err->error_type = MCE_ERROR_TYPE_SLB; 190 mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY; 191 } else if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) { 192 mce_err->error_type = MCE_ERROR_TYPE_TLB; 193 mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT; 194 } else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT_PARITY) { 195 mce_err->error_type = MCE_ERROR_TYPE_SLB; 196 mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE; 197 } 198 } 199 200 long __machine_check_early_realmode_p7(struct pt_regs *regs) 201 { 202 uint64_t srr1, addr; 203 long handled = 1; 204 struct mce_error_info mce_error_info = { 0 }; 205 206 srr1 = regs->msr; 207 208 /* 209 * Handle memory errors depending whether this was a load/store or 210 * ifetch exception. Also, populate the mce error_type and 211 * type-specific error_type from either SRR1 or DSISR, depending 212 * whether this was a load/store or ifetch exception 213 */ 214 if (P7_SRR1_MC_LOADSTORE(srr1)) { 215 handled = mce_handle_derror_p7(regs->dsisr); 216 mce_get_derror_p7(&mce_error_info, regs->dsisr); 217 addr = regs->dar; 218 } else { 219 handled = mce_handle_ierror_p7(srr1); 220 mce_get_ierror_p7(&mce_error_info, srr1); 221 addr = regs->nip; 222 } 223 224 save_mce_event(regs, handled, &mce_error_info, addr); 225 return handled; 226 } 227 228 static void mce_get_ierror_p8(struct mce_error_info *mce_err, uint64_t srr1) 229 { 230 mce_get_common_ierror(mce_err, srr1); 231 if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) { 232 mce_err->error_type = MCE_ERROR_TYPE_ERAT; 233 mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; 234 } 235 } 236 237 static void mce_get_derror_p8(struct mce_error_info *mce_err, uint64_t dsisr) 238 { 239 mce_get_derror_p7(mce_err, dsisr); 240 if (dsisr & P8_DSISR_MC_ERAT_MULTIHIT_SEC) { 241 mce_err->error_type = MCE_ERROR_TYPE_ERAT; 242 mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT; 243 } 244 } 245 246 static long mce_handle_ierror_p8(uint64_t srr1) 247 { 248 long handled = 0; 249 250 handled = mce_handle_common_ierror(srr1); 251 252 if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) { 253 flush_and_reload_slb(); 254 handled = 1; 255 } 256 return handled; 257 } 258 259 static long mce_handle_derror_p8(uint64_t dsisr) 260 { 261 return mce_handle_derror(dsisr, P8_DSISR_MC_SLB_ERRORS); 262 } 263 264 long __machine_check_early_realmode_p8(struct pt_regs *regs) 265 { 266 uint64_t srr1, addr; 267 long handled = 1; 268 struct mce_error_info mce_error_info = { 0 }; 269 270 srr1 = regs->msr; 271 272 if (P7_SRR1_MC_LOADSTORE(srr1)) { 273 handled = mce_handle_derror_p8(regs->dsisr); 274 mce_get_derror_p8(&mce_error_info, regs->dsisr); 275 addr = regs->dar; 276 } else { 277 handled = mce_handle_ierror_p8(srr1); 278 mce_get_ierror_p8(&mce_error_info, srr1); 279 addr = regs->nip; 280 } 281 282 save_mce_event(regs, handled, &mce_error_info, addr); 283 return handled; 284 } 285