0001
0002
0003
0004
0005
0006
0007
0008
0009 #undef DEBUG
0010 #define pr_fmt(fmt) "mce_power: " fmt
0011
0012 #include <linux/types.h>
0013 #include <linux/ptrace.h>
0014 #include <linux/extable.h>
0015 #include <linux/pgtable.h>
0016 #include <asm/mmu.h>
0017 #include <asm/mce.h>
0018 #include <asm/machdep.h>
0019 #include <asm/pte-walk.h>
0020 #include <asm/sstep.h>
0021 #include <asm/exception-64s.h>
0022 #include <asm/extable.h>
0023 #include <asm/inst.h>
0024
0025
0026
0027
0028
0029 unsigned long addr_to_pfn(struct pt_regs *regs, unsigned long addr)
0030 {
0031 pte_t *ptep, pte;
0032 unsigned int shift;
0033 unsigned long pfn, flags;
0034 struct mm_struct *mm;
0035
0036 if (user_mode(regs))
0037 mm = current->mm;
0038 else
0039 mm = &init_mm;
0040
0041 local_irq_save(flags);
0042 ptep = __find_linux_pte(mm->pgd, addr, NULL, &shift);
0043 if (!ptep) {
0044 pfn = ULONG_MAX;
0045 goto out;
0046 }
0047 pte = READ_ONCE(*ptep);
0048
0049 if (!pte_present(pte) || pte_special(pte)) {
0050 pfn = ULONG_MAX;
0051 goto out;
0052 }
0053
0054 if (shift <= PAGE_SHIFT)
0055 pfn = pte_pfn(pte);
0056 else {
0057 unsigned long rpnmask = (1ul << shift) - PAGE_SIZE;
0058 pfn = pte_pfn(__pte(pte_val(pte) | (addr & rpnmask)));
0059 }
0060 out:
0061 local_irq_restore(flags);
0062 return pfn;
0063 }
0064
0065 static bool mce_in_guest(void)
0066 {
0067 #ifdef CONFIG_KVM_BOOK3S_HANDLER
0068
0069
0070
0071
0072
0073 if (get_paca()->kvm_hstate.in_guest)
0074 return true;
0075 #endif
0076 return false;
0077 }
0078
0079
0080 #ifdef CONFIG_PPC_64S_HASH_MMU
0081 void flush_and_reload_slb(void)
0082 {
0083 if (early_radix_enabled())
0084 return;
0085
0086
0087 slb_flush_all_realmode();
0088
0089
0090
0091
0092
0093 if (!get_slb_shadow())
0094 return;
0095
0096 slb_restore_bolted_realmode();
0097 }
0098 #endif
0099
0100 void flush_erat(void)
0101 {
0102 #ifdef CONFIG_PPC_64S_HASH_MMU
0103 if (!early_cpu_has_feature(CPU_FTR_ARCH_300)) {
0104 flush_and_reload_slb();
0105 return;
0106 }
0107 #endif
0108 asm volatile(PPC_ISA_3_0_INVALIDATE_ERAT : : :"memory");
0109 }
0110
0111 #define MCE_FLUSH_SLB 1
0112 #define MCE_FLUSH_TLB 2
0113 #define MCE_FLUSH_ERAT 3
0114
0115 static int mce_flush(int what)
0116 {
0117 #ifdef CONFIG_PPC_64S_HASH_MMU
0118 if (what == MCE_FLUSH_SLB) {
0119 flush_and_reload_slb();
0120 return 1;
0121 }
0122 #endif
0123 if (what == MCE_FLUSH_ERAT) {
0124 flush_erat();
0125 return 1;
0126 }
0127 if (what == MCE_FLUSH_TLB) {
0128 tlbiel_all();
0129 return 1;
0130 }
0131
0132 return 0;
0133 }
0134
0135 #define SRR1_MC_LOADSTORE(srr1) ((srr1) & PPC_BIT(42))
0136
0137 struct mce_ierror_table {
0138 unsigned long srr1_mask;
0139 unsigned long srr1_value;
0140 bool nip_valid;
0141 unsigned int error_type;
0142 unsigned int error_subtype;
0143 unsigned int error_class;
0144 unsigned int initiator;
0145 unsigned int severity;
0146 bool sync_error;
0147 };
0148
0149 static const struct mce_ierror_table mce_p7_ierror_table[] = {
0150 { 0x00000000001c0000, 0x0000000000040000, true,
0151 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
0152 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0153 { 0x00000000001c0000, 0x0000000000080000, true,
0154 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
0155 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0156 { 0x00000000001c0000, 0x00000000000c0000, true,
0157 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0158 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0159 { 0x00000000001c0000, 0x0000000000100000, true,
0160 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE,
0161 MCE_ECLASS_SOFT_INDETERMINATE,
0162 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0163 { 0x00000000001c0000, 0x0000000000140000, true,
0164 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0165 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0166 { 0x00000000001c0000, 0x0000000000180000, true,
0167 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
0168 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0169 { 0x00000000001c0000, 0x00000000001c0000, true,
0170 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
0171 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0172 { 0, 0, 0, 0, 0, 0, 0 } };
0173
0174 static const struct mce_ierror_table mce_p8_ierror_table[] = {
0175 { 0x00000000081c0000, 0x0000000000040000, true,
0176 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
0177 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0178 { 0x00000000081c0000, 0x0000000000080000, true,
0179 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
0180 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0181 { 0x00000000081c0000, 0x00000000000c0000, true,
0182 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0183 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0184 { 0x00000000081c0000, 0x0000000000100000, true,
0185 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0186 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0187 { 0x00000000081c0000, 0x0000000000140000, true,
0188 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0189 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0190 { 0x00000000081c0000, 0x0000000000180000, true,
0191 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
0192 MCE_ECLASS_HARDWARE,
0193 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0194 { 0x00000000081c0000, 0x00000000001c0000, true,
0195 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
0196 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0197 { 0x00000000081c0000, 0x0000000008000000, true,
0198 MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_IFETCH_TIMEOUT, MCE_ECLASS_HARDWARE,
0199 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0200 { 0x00000000081c0000, 0x0000000008040000, true,
0201 MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
0202 MCE_ECLASS_HARDWARE,
0203 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0204 { 0, 0, 0, 0, 0, 0, 0 } };
0205
0206 static const struct mce_ierror_table mce_p9_ierror_table[] = {
0207 { 0x00000000081c0000, 0x0000000000040000, true,
0208 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
0209 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0210 { 0x00000000081c0000, 0x0000000000080000, true,
0211 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
0212 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0213 { 0x00000000081c0000, 0x00000000000c0000, true,
0214 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0215 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0216 { 0x00000000081c0000, 0x0000000000100000, true,
0217 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0218 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0219 { 0x00000000081c0000, 0x0000000000140000, true,
0220 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0221 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0222 { 0x00000000081c0000, 0x0000000000180000, true,
0223 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
0224 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0225 { 0x00000000081c0000, 0x00000000001c0000, true,
0226 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH_FOREIGN, MCE_ECLASS_SOFTWARE,
0227 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0228 { 0x00000000081c0000, 0x0000000008000000, true,
0229 MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_IFETCH_TIMEOUT, MCE_ECLASS_HARDWARE,
0230 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0231 { 0x00000000081c0000, 0x0000000008040000, true,
0232 MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
0233 MCE_ECLASS_HARDWARE,
0234 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0235 { 0x00000000081c0000, 0x00000000080c0000, true,
0236 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH, MCE_ECLASS_SOFTWARE,
0237 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0238 { 0x00000000081c0000, 0x0000000008100000, true,
0239 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_SOFTWARE,
0240 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0241 { 0x00000000081c0000, 0x0000000008140000, false,
0242 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_STORE, MCE_ECLASS_HARDWARE,
0243 MCE_INITIATOR_CPU, MCE_SEV_FATAL, false },
0244 { 0x00000000081c0000, 0x0000000008180000, false,
0245 MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_STORE_TIMEOUT,
0246 MCE_INITIATOR_CPU, MCE_SEV_FATAL, false },
0247 { 0x00000000081c0000, 0x00000000081c0000, true, MCE_ECLASS_HARDWARE,
0248 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
0249 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0250 { 0, 0, 0, 0, 0, 0, 0 } };
0251
0252 static const struct mce_ierror_table mce_p10_ierror_table[] = {
0253 { 0x00000000081c0000, 0x0000000000040000, true,
0254 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH, MCE_ECLASS_HARDWARE,
0255 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0256 { 0x00000000081c0000, 0x0000000000080000, true,
0257 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
0258 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0259 { 0x00000000081c0000, 0x00000000000c0000, true,
0260 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0261 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0262 { 0x00000000081c0000, 0x0000000000100000, true,
0263 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0264 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0265 { 0x00000000081c0000, 0x0000000000140000, true,
0266 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0267 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0268 { 0x00000000081c0000, 0x0000000000180000, true,
0269 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_HARDWARE,
0270 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0271 { 0x00000000081c0000, 0x00000000001c0000, true,
0272 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH_FOREIGN, MCE_ECLASS_SOFTWARE,
0273 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0274 { 0x00000000081c0000, 0x0000000008080000, true,
0275 MCE_ERROR_TYPE_USER,MCE_USER_ERROR_SCV, MCE_ECLASS_SOFTWARE,
0276 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0277 { 0x00000000081c0000, 0x00000000080c0000, true,
0278 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH, MCE_ECLASS_SOFTWARE,
0279 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0280 { 0x00000000081c0000, 0x0000000008100000, true,
0281 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH, MCE_ECLASS_SOFTWARE,
0282 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0283 { 0x00000000081c0000, 0x0000000008140000, false,
0284 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_STORE, MCE_ECLASS_HARDWARE,
0285 MCE_INITIATOR_CPU, MCE_SEV_FATAL, false },
0286 { 0x00000000081c0000, 0x00000000081c0000, true, MCE_ECLASS_HARDWARE,
0287 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
0288 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0289 { 0, 0, 0, 0, 0, 0, 0 } };
0290
0291 struct mce_derror_table {
0292 unsigned long dsisr_value;
0293 bool dar_valid;
0294 unsigned int error_type;
0295 unsigned int error_subtype;
0296 unsigned int error_class;
0297 unsigned int initiator;
0298 unsigned int severity;
0299 bool sync_error;
0300 };
0301
0302 static const struct mce_derror_table mce_p7_derror_table[] = {
0303 { 0x00008000, false,
0304 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
0305 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0306 { 0x00004000, true,
0307 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
0308 MCE_ECLASS_HARDWARE,
0309 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0310 { 0x00000800, true,
0311 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0312 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0313 { 0x00000400, true,
0314 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0315 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0316 { 0x00000080, true,
0317 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0318 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0319 { 0x00000100, true,
0320 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
0321 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0322 { 0x00000040, true,
0323 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE,
0324 MCE_ECLASS_HARD_INDETERMINATE,
0325 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0326 { 0, false, 0, 0, 0, 0, 0 } };
0327
0328 static const struct mce_derror_table mce_p8_derror_table[] = {
0329 { 0x00008000, false,
0330 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
0331 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0332 { 0x00004000, true,
0333 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
0334 MCE_ECLASS_HARDWARE,
0335 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0336 { 0x00002000, true,
0337 MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT, MCE_ECLASS_HARDWARE,
0338 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0339 { 0x00001000, true,
0340 MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
0341 MCE_ECLASS_HARDWARE,
0342 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0343 { 0x00000800, true,
0344 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0345 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0346 { 0x00000400, true,
0347 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0348 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0349 { 0x00000200, true,
0350 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT,
0351 MCE_ECLASS_SOFT_INDETERMINATE,
0352 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0353 { 0x00000080, true,
0354 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
0355 MCE_ECLASS_SOFT_INDETERMINATE,
0356 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0357 { 0x00000100, true,
0358 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
0359 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0360 { 0, false, 0, 0, 0, 0, 0 } };
0361
0362 static const struct mce_derror_table mce_p9_derror_table[] = {
0363 { 0x00008000, false,
0364 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
0365 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0366 { 0x00004000, true,
0367 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
0368 MCE_ECLASS_HARDWARE,
0369 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0370 { 0x00002000, true,
0371 MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT, MCE_ECLASS_HARDWARE,
0372 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0373 { 0x00001000, true,
0374 MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
0375 MCE_ECLASS_HARDWARE,
0376 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0377 { 0x00000800, true,
0378 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0379 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0380 { 0x00000400, true,
0381 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0382 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0383 { 0x00000200, false,
0384 MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE, MCE_ECLASS_SOFTWARE,
0385 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0386 { 0x00000080, true,
0387 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
0388 MCE_ECLASS_SOFT_INDETERMINATE,
0389 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0390 { 0x00000100, true,
0391 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
0392 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0393 { 0x00000040, true,
0394 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD, MCE_ECLASS_HARDWARE,
0395 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0396 { 0x00000020, false,
0397 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
0398 MCE_ECLASS_HARDWARE,
0399 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0400 { 0x00000010, false,
0401 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
0402 MCE_ECLASS_HARDWARE,
0403 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0404 { 0x00000008, false,
0405 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN, MCE_ECLASS_HARDWARE,
0406 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0407 { 0, false, 0, 0, 0, 0, 0 } };
0408
0409 static const struct mce_derror_table mce_p10_derror_table[] = {
0410 { 0x00008000, false,
0411 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE, MCE_ECLASS_HARDWARE,
0412 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0413 { 0x00004000, true,
0414 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
0415 MCE_ECLASS_HARDWARE,
0416 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0417 { 0x00000800, true,
0418 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0419 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0420 { 0x00000400, true,
0421 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT, MCE_ECLASS_SOFT_INDETERMINATE,
0422 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0423 { 0x00000200, false,
0424 MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE, MCE_ECLASS_SOFTWARE,
0425 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0426 { 0x00000080, true,
0427 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
0428 MCE_ECLASS_SOFT_INDETERMINATE,
0429 MCE_INITIATOR_CPU, MCE_SEV_WARNING, true },
0430 { 0x00000100, true,
0431 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY, MCE_ECLASS_HARD_INDETERMINATE,
0432 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0433 { 0x00000040, true,
0434 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD, MCE_ECLASS_HARDWARE,
0435 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0436 { 0x00000020, false,
0437 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
0438 MCE_ECLASS_HARDWARE,
0439 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0440 { 0x00000010, false,
0441 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
0442 MCE_ECLASS_HARDWARE,
0443 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0444 { 0x00000008, false,
0445 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN, MCE_ECLASS_HARDWARE,
0446 MCE_INITIATOR_CPU, MCE_SEV_SEVERE, true },
0447 { 0, false, 0, 0, 0, 0, 0 } };
0448
0449 static int mce_find_instr_ea_and_phys(struct pt_regs *regs, uint64_t *addr,
0450 uint64_t *phys_addr)
0451 {
0452
0453
0454
0455
0456
0457
0458 ppc_inst_t instr;
0459 unsigned long pfn, instr_addr;
0460 struct instruction_op op;
0461 struct pt_regs tmp = *regs;
0462
0463 pfn = addr_to_pfn(regs, regs->nip);
0464 if (pfn != ULONG_MAX) {
0465 instr_addr = (pfn << PAGE_SHIFT) + (regs->nip & ~PAGE_MASK);
0466 instr = ppc_inst_read((u32 *)instr_addr);
0467 if (!analyse_instr(&op, &tmp, instr)) {
0468 pfn = addr_to_pfn(regs, op.ea);
0469 *addr = op.ea;
0470 *phys_addr = (pfn << PAGE_SHIFT);
0471 return 0;
0472 }
0473
0474
0475
0476
0477
0478
0479 }
0480 *addr = 0;
0481 return -1;
0482 }
0483
0484 static int mce_handle_ierror(struct pt_regs *regs, unsigned long srr1,
0485 const struct mce_ierror_table table[],
0486 struct mce_error_info *mce_err, uint64_t *addr,
0487 uint64_t *phys_addr)
0488 {
0489 int handled = 0;
0490 int i;
0491
0492 *addr = 0;
0493
0494 for (i = 0; table[i].srr1_mask; i++) {
0495 if ((srr1 & table[i].srr1_mask) != table[i].srr1_value)
0496 continue;
0497
0498 if (!mce_in_guest()) {
0499
0500 switch (table[i].error_type) {
0501 case MCE_ERROR_TYPE_SLB:
0502 #ifdef CONFIG_PPC_64S_HASH_MMU
0503 if (local_paca->in_mce == 1)
0504 slb_save_contents(local_paca->mce_faulty_slbs);
0505 #endif
0506 handled = mce_flush(MCE_FLUSH_SLB);
0507 break;
0508 case MCE_ERROR_TYPE_ERAT:
0509 handled = mce_flush(MCE_FLUSH_ERAT);
0510 break;
0511 case MCE_ERROR_TYPE_TLB:
0512 handled = mce_flush(MCE_FLUSH_TLB);
0513 break;
0514 }
0515 }
0516
0517
0518 mce_err->error_type = table[i].error_type;
0519 mce_err->error_class = table[i].error_class;
0520 switch (table[i].error_type) {
0521 case MCE_ERROR_TYPE_UE:
0522 mce_err->u.ue_error_type = table[i].error_subtype;
0523 break;
0524 case MCE_ERROR_TYPE_SLB:
0525 mce_err->u.slb_error_type = table[i].error_subtype;
0526 break;
0527 case MCE_ERROR_TYPE_ERAT:
0528 mce_err->u.erat_error_type = table[i].error_subtype;
0529 break;
0530 case MCE_ERROR_TYPE_TLB:
0531 mce_err->u.tlb_error_type = table[i].error_subtype;
0532 break;
0533 case MCE_ERROR_TYPE_USER:
0534 mce_err->u.user_error_type = table[i].error_subtype;
0535 break;
0536 case MCE_ERROR_TYPE_RA:
0537 mce_err->u.ra_error_type = table[i].error_subtype;
0538 break;
0539 case MCE_ERROR_TYPE_LINK:
0540 mce_err->u.link_error_type = table[i].error_subtype;
0541 break;
0542 }
0543 mce_err->sync_error = table[i].sync_error;
0544 mce_err->severity = table[i].severity;
0545 mce_err->initiator = table[i].initiator;
0546 if (table[i].nip_valid && !mce_in_guest()) {
0547 *addr = regs->nip;
0548 if (mce_err->sync_error &&
0549 table[i].error_type == MCE_ERROR_TYPE_UE) {
0550 unsigned long pfn;
0551
0552 if (get_paca()->in_mce < MAX_MCE_DEPTH) {
0553 pfn = addr_to_pfn(regs, regs->nip);
0554 if (pfn != ULONG_MAX) {
0555 *phys_addr =
0556 (pfn << PAGE_SHIFT);
0557 }
0558 }
0559 }
0560 }
0561 return handled;
0562 }
0563
0564 mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
0565 mce_err->error_class = MCE_ECLASS_UNKNOWN;
0566 mce_err->severity = MCE_SEV_SEVERE;
0567 mce_err->initiator = MCE_INITIATOR_CPU;
0568 mce_err->sync_error = true;
0569
0570 return 0;
0571 }
0572
0573 static int mce_handle_derror(struct pt_regs *regs,
0574 const struct mce_derror_table table[],
0575 struct mce_error_info *mce_err, uint64_t *addr,
0576 uint64_t *phys_addr)
0577 {
0578 uint64_t dsisr = regs->dsisr;
0579 int handled = 0;
0580 int found = 0;
0581 int i;
0582
0583 *addr = 0;
0584
0585 for (i = 0; table[i].dsisr_value; i++) {
0586 if (!(dsisr & table[i].dsisr_value))
0587 continue;
0588
0589 if (!mce_in_guest()) {
0590
0591 switch (table[i].error_type) {
0592 case MCE_ERROR_TYPE_SLB:
0593 #ifdef CONFIG_PPC_64S_HASH_MMU
0594 if (local_paca->in_mce == 1)
0595 slb_save_contents(local_paca->mce_faulty_slbs);
0596 #endif
0597 if (mce_flush(MCE_FLUSH_SLB))
0598 handled = 1;
0599 break;
0600 case MCE_ERROR_TYPE_ERAT:
0601 if (mce_flush(MCE_FLUSH_ERAT))
0602 handled = 1;
0603 break;
0604 case MCE_ERROR_TYPE_TLB:
0605 if (mce_flush(MCE_FLUSH_TLB))
0606 handled = 1;
0607 break;
0608 }
0609 }
0610
0611
0612
0613
0614
0615
0616 if (found)
0617 continue;
0618
0619
0620 mce_err->error_type = table[i].error_type;
0621 mce_err->error_class = table[i].error_class;
0622 switch (table[i].error_type) {
0623 case MCE_ERROR_TYPE_UE:
0624 mce_err->u.ue_error_type = table[i].error_subtype;
0625 break;
0626 case MCE_ERROR_TYPE_SLB:
0627 mce_err->u.slb_error_type = table[i].error_subtype;
0628 break;
0629 case MCE_ERROR_TYPE_ERAT:
0630 mce_err->u.erat_error_type = table[i].error_subtype;
0631 break;
0632 case MCE_ERROR_TYPE_TLB:
0633 mce_err->u.tlb_error_type = table[i].error_subtype;
0634 break;
0635 case MCE_ERROR_TYPE_USER:
0636 mce_err->u.user_error_type = table[i].error_subtype;
0637 break;
0638 case MCE_ERROR_TYPE_RA:
0639 mce_err->u.ra_error_type = table[i].error_subtype;
0640 break;
0641 case MCE_ERROR_TYPE_LINK:
0642 mce_err->u.link_error_type = table[i].error_subtype;
0643 break;
0644 }
0645 mce_err->sync_error = table[i].sync_error;
0646 mce_err->severity = table[i].severity;
0647 mce_err->initiator = table[i].initiator;
0648 if (table[i].dar_valid)
0649 *addr = regs->dar;
0650 else if (mce_err->sync_error && !mce_in_guest() &&
0651 table[i].error_type == MCE_ERROR_TYPE_UE) {
0652
0653
0654
0655
0656 if (get_paca()->in_mce < MAX_MCE_DEPTH)
0657 mce_find_instr_ea_and_phys(regs, addr,
0658 phys_addr);
0659 }
0660 found = 1;
0661 }
0662
0663 if (found)
0664 return handled;
0665
0666 mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
0667 mce_err->error_class = MCE_ECLASS_UNKNOWN;
0668 mce_err->severity = MCE_SEV_SEVERE;
0669 mce_err->initiator = MCE_INITIATOR_CPU;
0670 mce_err->sync_error = true;
0671
0672 return 0;
0673 }
0674
0675 static long mce_handle_ue_error(struct pt_regs *regs,
0676 struct mce_error_info *mce_err)
0677 {
0678 if (mce_in_guest())
0679 return 0;
0680
0681 mce_common_process_ue(regs, mce_err);
0682 if (mce_err->ignore_event)
0683 return 1;
0684
0685
0686
0687
0688
0689
0690
0691
0692 if (ppc_md.mce_check_early_recovery) {
0693 if (ppc_md.mce_check_early_recovery(regs))
0694 return 1;
0695 }
0696
0697 return 0;
0698 }
0699
0700 static long mce_handle_error(struct pt_regs *regs,
0701 unsigned long srr1,
0702 const struct mce_derror_table dtable[],
0703 const struct mce_ierror_table itable[])
0704 {
0705 struct mce_error_info mce_err = { 0 };
0706 uint64_t addr, phys_addr = ULONG_MAX;
0707 long handled;
0708
0709 if (SRR1_MC_LOADSTORE(srr1))
0710 handled = mce_handle_derror(regs, dtable, &mce_err, &addr,
0711 &phys_addr);
0712 else
0713 handled = mce_handle_ierror(regs, srr1, itable, &mce_err, &addr,
0714 &phys_addr);
0715
0716 if (!handled && mce_err.error_type == MCE_ERROR_TYPE_UE)
0717 handled = mce_handle_ue_error(regs, &mce_err);
0718
0719 save_mce_event(regs, handled, &mce_err, regs->nip, addr, phys_addr);
0720
0721 return handled;
0722 }
0723
0724 long __machine_check_early_realmode_p7(struct pt_regs *regs)
0725 {
0726
0727 regs->dsisr &= 0x0000ffff;
0728
0729 return mce_handle_error(regs, regs->msr,
0730 mce_p7_derror_table, mce_p7_ierror_table);
0731 }
0732
0733 long __machine_check_early_realmode_p8(struct pt_regs *regs)
0734 {
0735 return mce_handle_error(regs, regs->msr,
0736 mce_p8_derror_table, mce_p8_ierror_table);
0737 }
0738
0739 long __machine_check_early_realmode_p9(struct pt_regs *regs)
0740 {
0741 unsigned long srr1 = regs->msr;
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753 if (SRR1_MC_LOADSTORE(regs->msr) && regs->dsisr == 0x02000000)
0754 return 1;
0755
0756
0757
0758
0759
0760
0761
0762
0763 if (SRR1_MC_LOADSTORE(srr1) &&
0764 ((srr1 & 0x081c0000) == 0x08140000 ||
0765 (srr1 & 0x081c0000) == 0x08180000)) {
0766 srr1 &= ~PPC_BIT(42);
0767 }
0768
0769 return mce_handle_error(regs, srr1,
0770 mce_p9_derror_table, mce_p9_ierror_table);
0771 }
0772
0773 long __machine_check_early_realmode_p10(struct pt_regs *regs)
0774 {
0775 unsigned long srr1 = regs->msr;
0776
0777
0778
0779
0780
0781
0782
0783
0784 if (SRR1_MC_LOADSTORE(srr1) &&
0785 (srr1 & 0x081c0000) == 0x08140000) {
0786 srr1 &= ~PPC_BIT(42);
0787 }
0788
0789 return mce_handle_error(regs, srr1,
0790 mce_p10_derror_table, mce_p10_ierror_table);
0791 }