blob: de242b4bbd20b5c019c1d19072d3ee30818b9c26 [file] [log] [blame]
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +05301/*
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>
Mahesh Salgaonkar55672ec2013-12-16 10:46:24 +053029#include <asm/machdep.h>
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +053030
Mahesh Salgaonkar45706bb2014-12-19 08:41:05 +053031static void flush_tlb_206(unsigned int num_sets, unsigned int action)
32{
33 unsigned long rb;
34 unsigned int i;
35
36 switch (action) {
37 case TLB_INVAL_SCOPE_GLOBAL:
38 rb = TLBIEL_INVAL_SET;
39 break;
40 case TLB_INVAL_SCOPE_LPID:
41 rb = TLBIEL_INVAL_SET_LPID;
42 break;
43 default:
44 BUG();
45 break;
46 }
47
48 asm volatile("ptesync" : : : "memory");
49 for (i = 0; i < num_sets; i++) {
50 asm volatile("tlbiel %0" : : "r" (rb));
51 rb += 1 << TLBIEL_INVAL_SET_SHIFT;
52 }
53 asm volatile("ptesync" : : : "memory");
54}
55
56/*
Michael Neulingc3ab3002016-02-19 11:16:24 +110057 * Generic routines to flush TLB on POWER processors. These routines
58 * are used as flush_tlb hook in the cpu_spec.
Mahesh Salgaonkar45706bb2014-12-19 08:41:05 +053059 *
60 * action => TLB_INVAL_SCOPE_GLOBAL: Invalidate all TLBs.
61 * TLB_INVAL_SCOPE_LPID: Invalidate TLB for current LPID.
62 */
63void __flush_tlb_power7(unsigned int action)
64{
65 flush_tlb_206(POWER7_TLB_SETS, action);
66}
67
Mahesh Salgaonkar45706bb2014-12-19 08:41:05 +053068void __flush_tlb_power8(unsigned int action)
69{
70 flush_tlb_206(POWER8_TLB_SETS, action);
71}
72
Michael Neulingc3ab3002016-02-19 11:16:24 +110073void __flush_tlb_power9(unsigned int action)
74{
Aneesh Kumar K.V1a472c92016-04-29 23:26:05 +100075 if (radix_enabled())
76 flush_tlb_206(POWER9_TLB_SETS_RADIX, action);
77
Michael Neulingc3ab3002016-02-19 11:16:24 +110078 flush_tlb_206(POWER9_TLB_SETS_HASH, action);
79}
80
81
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +053082/* flush SLBs and reload */
Valentin Rothbergbb03efe2016-05-03 08:59:27 +020083#ifdef CONFIG_PPC_STD_MMU_64
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +053084static void flush_and_reload_slb(void)
85{
86 struct slb_shadow *slb;
87 unsigned long i, n;
88
89 /* Invalidate all SLBs */
90 asm volatile("slbmte %0,%0; slbia" : : "r" (0));
91
92#ifdef CONFIG_KVM_BOOK3S_HANDLER
93 /*
94 * If machine check is hit when in guest or in transition, we will
95 * only flush the SLBs and continue.
96 */
97 if (get_paca()->kvm_hstate.in_guest)
98 return;
99#endif
100
101 /* For host kernel, reload the SLBs from shadow SLB buffer. */
102 slb = get_slb_shadow();
103 if (!slb)
104 return;
105
Anton Blancharda68c33f2013-12-16 10:47:54 +1100106 n = min_t(u32, be32_to_cpu(slb->persistent), SLB_MIN_SIZE);
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +0530107
108 /* Load up the SLB entries from shadow SLB */
109 for (i = 0; i < n; i++) {
Anton Blancharda68c33f2013-12-16 10:47:54 +1100110 unsigned long rb = be64_to_cpu(slb->save_area[i].esid);
111 unsigned long rs = be64_to_cpu(slb->save_area[i].vsid);
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +0530112
113 rb = (rb & ~0xFFFul) | i;
114 asm volatile("slbmte %0,%1" : : "r" (rs), "r" (rb));
115 }
116}
Aneesh Kumar K.Vcaca2852016-04-29 23:26:07 +1000117#endif
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +0530118
Nicholas Piggin7b9f71f92017-02-28 12:00:48 +1000119static void flush_erat(void)
120{
121 asm volatile(PPC_INVALIDATE_ERAT : : :"memory");
122}
123
124#define MCE_FLUSH_SLB 1
125#define MCE_FLUSH_TLB 2
126#define MCE_FLUSH_ERAT 3
127
128static int mce_flush(int what)
129{
130#ifdef CONFIG_PPC_STD_MMU_64
131 if (what == MCE_FLUSH_SLB) {
132 flush_and_reload_slb();
133 return 1;
134 }
135#endif
136 if (what == MCE_FLUSH_ERAT) {
137 flush_erat();
138 return 1;
139 }
140 if (what == MCE_FLUSH_TLB) {
141 if (cur_cpu_spec && cur_cpu_spec->flush_tlb) {
142 cur_cpu_spec->flush_tlb(TLB_INVAL_SCOPE_GLOBAL);
143 return 1;
144 }
145 }
146
147 return 0;
148}
149
Nicholas Piggin755309b2017-03-14 22:36:47 +1000150#define SRR1_MC_LOADSTORE(srr1) ((srr1) & PPC_BIT(42))
Nicholas Piggin58c8d172017-03-14 22:36:45 +1000151
Nicholas Piggin631bc462017-03-14 22:36:46 +1000152struct mce_ierror_table {
153 unsigned long srr1_mask;
154 unsigned long srr1_value;
155 bool nip_valid; /* nip is a valid indicator of faulting address */
156 unsigned int error_type;
157 unsigned int error_subtype;
158 unsigned int initiator;
159 unsigned int severity;
160};
161
162static const struct mce_ierror_table mce_p7_ierror_table[] = {
163{ 0x00000000001c0000, 0x0000000000040000, true,
164 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
165 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
166{ 0x00000000001c0000, 0x0000000000080000, true,
167 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
168 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
169{ 0x00000000001c0000, 0x00000000000c0000, true,
170 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
171 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
172{ 0x00000000001c0000, 0x0000000000100000, true,
173 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE, /* BOTH */
174 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
175{ 0x00000000001c0000, 0x0000000000140000, true,
176 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
177 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
178{ 0x00000000001c0000, 0x0000000000180000, true,
179 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
180 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
181{ 0x00000000001c0000, 0x00000000001c0000, true,
182 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
183 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
184{ 0, 0, 0, 0, 0, 0 } };
185
186static const struct mce_ierror_table mce_p8_ierror_table[] = {
Nicholas Pigginc7e790c2017-03-14 22:36:48 +1000187{ 0x00000000081c0000, 0x0000000000040000, true,
Nicholas Piggin631bc462017-03-14 22:36:46 +1000188 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
189 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Nicholas Pigginc7e790c2017-03-14 22:36:48 +1000190{ 0x00000000081c0000, 0x0000000000080000, true,
Nicholas Piggin631bc462017-03-14 22:36:46 +1000191 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
192 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Nicholas Pigginc7e790c2017-03-14 22:36:48 +1000193{ 0x00000000081c0000, 0x00000000000c0000, true,
Nicholas Piggin631bc462017-03-14 22:36:46 +1000194 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
195 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Nicholas Pigginc7e790c2017-03-14 22:36:48 +1000196{ 0x00000000081c0000, 0x0000000000100000, true,
Nicholas Piggin631bc462017-03-14 22:36:46 +1000197 MCE_ERROR_TYPE_ERAT,MCE_ERAT_ERROR_MULTIHIT,
198 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Nicholas Pigginc7e790c2017-03-14 22:36:48 +1000199{ 0x00000000081c0000, 0x0000000000140000, true,
Nicholas Piggin631bc462017-03-14 22:36:46 +1000200 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
201 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Nicholas Pigginc7e790c2017-03-14 22:36:48 +1000202{ 0x00000000081c0000, 0x0000000000180000, true,
Nicholas Piggin631bc462017-03-14 22:36:46 +1000203 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
204 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Nicholas Pigginc7e790c2017-03-14 22:36:48 +1000205{ 0x00000000081c0000, 0x00000000001c0000, true,
Nicholas Piggin631bc462017-03-14 22:36:46 +1000206 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
207 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Nicholas Pigginc7e790c2017-03-14 22:36:48 +1000208{ 0x00000000081c0000, 0x0000000008000000, true,
209 MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_IFETCH_TIMEOUT,
210 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
211{ 0x00000000081c0000, 0x0000000008040000, true,
212 MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
213 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Nicholas Piggin631bc462017-03-14 22:36:46 +1000214{ 0, 0, 0, 0, 0, 0 } };
215
216static const struct mce_ierror_table mce_p9_ierror_table[] = {
217{ 0x00000000081c0000, 0x0000000000040000, true,
218 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_IFETCH,
219 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
220{ 0x00000000081c0000, 0x0000000000080000, true,
221 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
222 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
223{ 0x00000000081c0000, 0x00000000000c0000, true,
224 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
225 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
226{ 0x00000000081c0000, 0x0000000000100000, true,
227 MCE_ERROR_TYPE_ERAT,MCE_ERAT_ERROR_MULTIHIT,
228 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
229{ 0x00000000081c0000, 0x0000000000140000, true,
230 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
231 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
232{ 0x00000000081c0000, 0x0000000000180000, true,
233 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH,
234 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
235{ 0x00000000081c0000, 0x0000000008000000, true,
236 MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_IFETCH_TIMEOUT,
237 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
238{ 0x00000000081c0000, 0x0000000008040000, true,
239 MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT,
240 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
241{ 0x00000000081c0000, 0x00000000080c0000, true,
242 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_IFETCH,
243 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
244{ 0x00000000081c0000, 0x0000000008100000, true,
245 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH,
246 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
247{ 0x00000000081c0000, 0x0000000008140000, false,
248 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_STORE,
249 MCE_INITIATOR_CPU, MCE_SEV_FATAL, }, /* ASYNC is fatal */
250{ 0x00000000081c0000, 0x0000000008180000, false,
251 MCE_ERROR_TYPE_LINK,MCE_LINK_ERROR_STORE_TIMEOUT,
252 MCE_INITIATOR_CPU, MCE_SEV_FATAL, }, /* ASYNC is fatal */
253{ 0x00000000081c0000, 0x00000000081c0000, true,
254 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN,
255 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
256{ 0, 0, 0, 0, 0, 0 } };
257
258struct mce_derror_table {
259 unsigned long dsisr_value;
260 bool dar_valid; /* dar is a valid indicator of faulting address */
261 unsigned int error_type;
262 unsigned int error_subtype;
263 unsigned int initiator;
264 unsigned int severity;
265};
266
267static const struct mce_derror_table mce_p7_derror_table[] = {
268{ 0x00008000, false,
269 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE,
270 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
271{ 0x00004000, true,
272 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
273 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
274{ 0x00000800, true,
275 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT,
276 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
277{ 0x00000400, true,
278 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
279 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
280{ 0x00000100, true,
281 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
282 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
283{ 0x00000080, true,
284 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
285 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
286{ 0x00000040, true,
287 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_INDETERMINATE, /* BOTH */
288 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
289{ 0, false, 0, 0, 0, 0 } };
290
291static const struct mce_derror_table mce_p8_derror_table[] = {
292{ 0x00008000, false,
293 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE,
294 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
295{ 0x00004000, true,
296 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
297 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Nicholas Pigginc7e790c2017-03-14 22:36:48 +1000298{ 0x00002000, true,
299 MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT,
300 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
301{ 0x00001000, true,
302 MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
303 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Nicholas Piggin631bc462017-03-14 22:36:46 +1000304{ 0x00000800, true,
305 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT,
306 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
307{ 0x00000400, true,
308 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
309 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
310{ 0x00000200, true,
311 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT, /* SECONDARY ERAT */
312 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
313{ 0x00000100, true,
314 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
315 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
316{ 0x00000080, true,
317 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
318 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
319{ 0, false, 0, 0, 0, 0 } };
320
321static const struct mce_derror_table mce_p9_derror_table[] = {
322{ 0x00008000, false,
323 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_LOAD_STORE,
324 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
325{ 0x00004000, true,
326 MCE_ERROR_TYPE_UE, MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
327 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
328{ 0x00002000, true,
329 MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_LOAD_TIMEOUT,
330 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
331{ 0x00001000, true,
332 MCE_ERROR_TYPE_LINK, MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT,
333 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
334{ 0x00000800, true,
335 MCE_ERROR_TYPE_ERAT, MCE_ERAT_ERROR_MULTIHIT,
336 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
337{ 0x00000400, true,
338 MCE_ERROR_TYPE_TLB, MCE_TLB_ERROR_MULTIHIT,
339 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
340{ 0x00000200, false,
341 MCE_ERROR_TYPE_USER, MCE_USER_ERROR_TLBIE,
342 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
343{ 0x00000100, true,
344 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_PARITY,
345 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
346{ 0x00000080, true,
347 MCE_ERROR_TYPE_SLB, MCE_SLB_ERROR_MULTIHIT,
348 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
349{ 0x00000040, true,
350 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD,
351 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
352{ 0x00000020, false,
353 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE,
354 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
355{ 0x00000010, false,
356 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN,
357 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
358{ 0x00000008, false,
359 MCE_ERROR_TYPE_RA, MCE_RA_ERROR_LOAD_STORE_FOREIGN,
360 MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
361{ 0, false, 0, 0, 0, 0 } };
362
Nicholas Piggin755309b2017-03-14 22:36:47 +1000363static int mce_handle_ierror(struct pt_regs *regs,
Nicholas Piggin631bc462017-03-14 22:36:46 +1000364 const struct mce_ierror_table table[],
365 struct mce_error_info *mce_err, uint64_t *addr)
366{
367 uint64_t srr1 = regs->msr;
Nicholas Piggin755309b2017-03-14 22:36:47 +1000368 int handled = 0;
Nicholas Piggin631bc462017-03-14 22:36:46 +1000369 int i;
370
371 *addr = 0;
372
373 for (i = 0; table[i].srr1_mask; i++) {
374 if ((srr1 & table[i].srr1_mask) != table[i].srr1_value)
375 continue;
376
Nicholas Piggin755309b2017-03-14 22:36:47 +1000377 /* attempt to correct the error */
378 switch (table[i].error_type) {
379 case MCE_ERROR_TYPE_SLB:
380 handled = mce_flush(MCE_FLUSH_SLB);
381 break;
382 case MCE_ERROR_TYPE_ERAT:
383 handled = mce_flush(MCE_FLUSH_ERAT);
384 break;
385 case MCE_ERROR_TYPE_TLB:
386 handled = mce_flush(MCE_FLUSH_TLB);
387 break;
388 }
389
390 /* now fill in mce_error_info */
Nicholas Piggin631bc462017-03-14 22:36:46 +1000391 mce_err->error_type = table[i].error_type;
392 switch (table[i].error_type) {
393 case MCE_ERROR_TYPE_UE:
394 mce_err->u.ue_error_type = table[i].error_subtype;
395 break;
396 case MCE_ERROR_TYPE_SLB:
397 mce_err->u.slb_error_type = table[i].error_subtype;
398 break;
399 case MCE_ERROR_TYPE_ERAT:
400 mce_err->u.erat_error_type = table[i].error_subtype;
401 break;
402 case MCE_ERROR_TYPE_TLB:
403 mce_err->u.tlb_error_type = table[i].error_subtype;
404 break;
405 case MCE_ERROR_TYPE_USER:
406 mce_err->u.user_error_type = table[i].error_subtype;
407 break;
408 case MCE_ERROR_TYPE_RA:
409 mce_err->u.ra_error_type = table[i].error_subtype;
410 break;
411 case MCE_ERROR_TYPE_LINK:
412 mce_err->u.link_error_type = table[i].error_subtype;
413 break;
414 }
415 mce_err->severity = table[i].severity;
416 mce_err->initiator = table[i].initiator;
417 if (table[i].nip_valid)
418 *addr = regs->nip;
Nicholas Piggin755309b2017-03-14 22:36:47 +1000419 return handled;
Nicholas Piggin631bc462017-03-14 22:36:46 +1000420 }
421
422 mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
423 mce_err->severity = MCE_SEV_ERROR_SYNC;
424 mce_err->initiator = MCE_INITIATOR_CPU;
Nicholas Piggin755309b2017-03-14 22:36:47 +1000425
426 return 0;
Nicholas Piggin631bc462017-03-14 22:36:46 +1000427}
428
Nicholas Piggin755309b2017-03-14 22:36:47 +1000429static int mce_handle_derror(struct pt_regs *regs,
Nicholas Piggin631bc462017-03-14 22:36:46 +1000430 const struct mce_derror_table table[],
431 struct mce_error_info *mce_err, uint64_t *addr)
432{
433 uint64_t dsisr = regs->dsisr;
Nicholas Piggin755309b2017-03-14 22:36:47 +1000434 int handled = 0;
435 int found = 0;
Nicholas Piggin631bc462017-03-14 22:36:46 +1000436 int i;
437
438 *addr = 0;
439
440 for (i = 0; table[i].dsisr_value; i++) {
441 if (!(dsisr & table[i].dsisr_value))
442 continue;
443
Nicholas Piggin755309b2017-03-14 22:36:47 +1000444 /* attempt to correct the error */
445 switch (table[i].error_type) {
446 case MCE_ERROR_TYPE_SLB:
447 if (mce_flush(MCE_FLUSH_SLB))
448 handled = 1;
449 break;
450 case MCE_ERROR_TYPE_ERAT:
451 if (mce_flush(MCE_FLUSH_ERAT))
452 handled = 1;
453 break;
454 case MCE_ERROR_TYPE_TLB:
455 if (mce_flush(MCE_FLUSH_TLB))
456 handled = 1;
457 break;
458 }
459
460 /*
461 * Attempt to handle multiple conditions, but only return
462 * one. Ensure uncorrectable errors are first in the table
463 * to match.
464 */
465 if (found)
466 continue;
467
468 /* now fill in mce_error_info */
Nicholas Piggin631bc462017-03-14 22:36:46 +1000469 mce_err->error_type = table[i].error_type;
470 switch (table[i].error_type) {
471 case MCE_ERROR_TYPE_UE:
472 mce_err->u.ue_error_type = table[i].error_subtype;
473 break;
474 case MCE_ERROR_TYPE_SLB:
475 mce_err->u.slb_error_type = table[i].error_subtype;
476 break;
477 case MCE_ERROR_TYPE_ERAT:
478 mce_err->u.erat_error_type = table[i].error_subtype;
479 break;
480 case MCE_ERROR_TYPE_TLB:
481 mce_err->u.tlb_error_type = table[i].error_subtype;
482 break;
483 case MCE_ERROR_TYPE_USER:
484 mce_err->u.user_error_type = table[i].error_subtype;
485 break;
486 case MCE_ERROR_TYPE_RA:
487 mce_err->u.ra_error_type = table[i].error_subtype;
488 break;
489 case MCE_ERROR_TYPE_LINK:
490 mce_err->u.link_error_type = table[i].error_subtype;
491 break;
492 }
493 mce_err->severity = table[i].severity;
494 mce_err->initiator = table[i].initiator;
495 if (table[i].dar_valid)
496 *addr = regs->dar;
497
Nicholas Piggin755309b2017-03-14 22:36:47 +1000498 found = 1;
Nicholas Piggin631bc462017-03-14 22:36:46 +1000499 }
500
Nicholas Piggin755309b2017-03-14 22:36:47 +1000501 if (found)
502 return handled;
503
Nicholas Piggin631bc462017-03-14 22:36:46 +1000504 mce_err->error_type = MCE_ERROR_TYPE_UNKNOWN;
505 mce_err->severity = MCE_SEV_ERROR_SYNC;
506 mce_err->initiator = MCE_INITIATOR_CPU;
Nicholas Piggin755309b2017-03-14 22:36:47 +1000507
508 return 0;
Nicholas Piggin631bc462017-03-14 22:36:46 +1000509}
510
511static long mce_handle_ue_error(struct pt_regs *regs)
512{
513 long handled = 0;
514
515 /*
516 * On specific SCOM read via MMIO we may get a machine check
517 * exception with SRR0 pointing inside opal. If that is the
518 * case OPAL may have recovery address to re-read SCOM data in
519 * different way and hence we can recover from this MC.
520 */
521
522 if (ppc_md.mce_check_early_recovery) {
523 if (ppc_md.mce_check_early_recovery(regs))
524 handled = 1;
525 }
526 return handled;
527}
528
Nicholas Piggin755309b2017-03-14 22:36:47 +1000529static long mce_handle_error(struct pt_regs *regs,
530 const struct mce_derror_table dtable[],
531 const struct mce_ierror_table itable[])
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +0530532{
Nicholas Piggin755309b2017-03-14 22:36:47 +1000533 struct mce_error_info mce_err = { 0 };
534 uint64_t addr;
535 uint64_t srr1 = regs->msr;
536 long handled;
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +0530537
Nicholas Piggin755309b2017-03-14 22:36:47 +1000538 if (SRR1_MC_LOADSTORE(srr1))
539 handled = mce_handle_derror(regs, dtable, &mce_err, &addr);
540 else
541 handled = mce_handle_ierror(regs, itable, &mce_err, &addr);
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +0530542
Nicholas Piggin755309b2017-03-14 22:36:47 +1000543 if (!handled && mce_err.error_type == MCE_ERROR_TYPE_UE)
544 handled = mce_handle_ue_error(regs);
545
546 save_mce_event(regs, handled, &mce_err, regs->nip, addr);
547
548 return handled;
Mahesh Salgaonkare22a2272013-10-30 20:05:11 +0530549}
550
551long __machine_check_early_realmode_p7(struct pt_regs *regs)
552{
Nicholas Piggin631bc462017-03-14 22:36:46 +1000553 /* P7 DD1 leaves top bits of DSISR undefined */
554 regs->dsisr &= 0x0000ffff;
555
Nicholas Piggin755309b2017-03-14 22:36:47 +1000556 return mce_handle_error(regs, mce_p7_derror_table, mce_p7_ierror_table);
Mahesh Salgaonkarae744f32013-10-30 20:05:26 +0530557}
558
559long __machine_check_early_realmode_p8(struct pt_regs *regs)
560{
Nicholas Piggin755309b2017-03-14 22:36:47 +1000561 return mce_handle_error(regs, mce_p8_derror_table, mce_p8_ierror_table);
Nicholas Piggin7b9f71f92017-02-28 12:00:48 +1000562}
563
Nicholas Piggin7b9f71f92017-02-28 12:00:48 +1000564long __machine_check_early_realmode_p9(struct pt_regs *regs)
565{
Nicholas Piggin755309b2017-03-14 22:36:47 +1000566 return mce_handle_error(regs, mce_p9_derror_table, mce_p9_ierror_table);
Nicholas Piggin7b9f71f92017-02-28 12:00:48 +1000567}