forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-06 08f87f769b595151be1afeff53e144f543faa614
kernel/arch/powerpc/platforms/pseries/ras.c
....@@ -1,19 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright (C) 2001 Dave Engebretsen IBM Corporation
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
174 */
185
196 #include <linux/sched.h>
....@@ -27,6 +14,7 @@
2714 #include <asm/machdep.h>
2815 #include <asm/rtas.h>
2916 #include <asm/firmware.h>
17
+#include <asm/mce.h>
3018
3119 #include "pseries.h"
3220
....@@ -50,6 +38,84 @@
5038 static irqreturn_t ras_epow_interrupt(int irq, void *dev_id);
5139 static irqreturn_t ras_error_interrupt(int irq, void *dev_id);
5240
41
+/* RTAS pseries MCE errorlog section. */
42
+struct pseries_mc_errorlog {
43
+ __be32 fru_id;
44
+ __be32 proc_id;
45
+ u8 error_type;
46
+ /*
47
+ * sub_err_type (1 byte). Bit fields depends on error_type
48
+ *
49
+ * MSB0
50
+ * |
51
+ * V
52
+ * 01234567
53
+ * XXXXXXXX
54
+ *
55
+ * For error_type == MC_ERROR_TYPE_UE
56
+ * XXXXXXXX
57
+ * X 1: Permanent or Transient UE.
58
+ * X 1: Effective address provided.
59
+ * X 1: Logical address provided.
60
+ * XX 2: Reserved.
61
+ * XXX 3: Type of UE error.
62
+ *
63
+ * For error_type != MC_ERROR_TYPE_UE
64
+ * XXXXXXXX
65
+ * X 1: Effective address provided.
66
+ * XXXXX 5: Reserved.
67
+ * XX 2: Type of SLB/ERAT/TLB error.
68
+ */
69
+ u8 sub_err_type;
70
+ u8 reserved_1[6];
71
+ __be64 effective_address;
72
+ __be64 logical_address;
73
+} __packed;
74
+
75
+/* RTAS pseries MCE error types */
76
+#define MC_ERROR_TYPE_UE 0x00
77
+#define MC_ERROR_TYPE_SLB 0x01
78
+#define MC_ERROR_TYPE_ERAT 0x02
79
+#define MC_ERROR_TYPE_UNKNOWN 0x03
80
+#define MC_ERROR_TYPE_TLB 0x04
81
+#define MC_ERROR_TYPE_D_CACHE 0x05
82
+#define MC_ERROR_TYPE_I_CACHE 0x07
83
+
84
+/* RTAS pseries MCE error sub types */
85
+#define MC_ERROR_UE_INDETERMINATE 0
86
+#define MC_ERROR_UE_IFETCH 1
87
+#define MC_ERROR_UE_PAGE_TABLE_WALK_IFETCH 2
88
+#define MC_ERROR_UE_LOAD_STORE 3
89
+#define MC_ERROR_UE_PAGE_TABLE_WALK_LOAD_STORE 4
90
+
91
+#define UE_EFFECTIVE_ADDR_PROVIDED 0x40
92
+#define UE_LOGICAL_ADDR_PROVIDED 0x20
93
+
94
+#define MC_ERROR_SLB_PARITY 0
95
+#define MC_ERROR_SLB_MULTIHIT 1
96
+#define MC_ERROR_SLB_INDETERMINATE 2
97
+
98
+#define MC_ERROR_ERAT_PARITY 1
99
+#define MC_ERROR_ERAT_MULTIHIT 2
100
+#define MC_ERROR_ERAT_INDETERMINATE 3
101
+
102
+#define MC_ERROR_TLB_PARITY 1
103
+#define MC_ERROR_TLB_MULTIHIT 2
104
+#define MC_ERROR_TLB_INDETERMINATE 3
105
+
106
+static inline u8 rtas_mc_error_sub_type(const struct pseries_mc_errorlog *mlog)
107
+{
108
+ switch (mlog->error_type) {
109
+ case MC_ERROR_TYPE_UE:
110
+ return (mlog->sub_err_type & 0x07);
111
+ case MC_ERROR_TYPE_SLB:
112
+ case MC_ERROR_TYPE_ERAT:
113
+ case MC_ERROR_TYPE_TLB:
114
+ return (mlog->sub_err_type & 0x03);
115
+ default:
116
+ return 0;
117
+ }
118
+}
53119
54120 /*
55121 * Enable the hotplug interrupt late because processing them may touch other
....@@ -188,7 +254,7 @@
188254 break;
189255
190256 case EPOW_SYSTEM_SHUTDOWN:
191
- handle_system_shutdown(epow_log->event_modifier);
257
+ handle_system_shutdown(modifier);
192258 break;
193259
194260 case EPOW_SYSTEM_HALT:
....@@ -236,8 +302,9 @@
236302 * hotplug events on the ras_log_buf to be handled by rtas_errd.
237303 */
238304 if (hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_MEM ||
239
- hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU)
240
- queue_hotplug_event(hp_elog, NULL, NULL);
305
+ hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_CPU ||
306
+ hp_elog->resource == PSERIES_HP_ELOG_RESOURCE_PMEM)
307
+ queue_hotplug_event(hp_elog);
241308 else
242309 log_error(ras_log_buf, ERR_TYPE_RTAS_LOG, 0);
243310
....@@ -338,6 +405,20 @@
338405 return (struct rtas_error_log *)local_paca->mce_data_buf;
339406 }
340407
408
+static __be64 *fwnmi_get_savep(struct pt_regs *regs)
409
+{
410
+ unsigned long savep_ra;
411
+
412
+ /* Mask top two bits */
413
+ savep_ra = regs->gpr[3] & ~(0x3UL << 62);
414
+ if (!VALID_FWNMI_BUFFER(savep_ra)) {
415
+ printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]);
416
+ return NULL;
417
+ }
418
+
419
+ return __va(savep_ra);
420
+}
421
+
341422 /*
342423 * Get the error information for errors coming through the
343424 * FWNMI vectors. The pt_regs' r3 will be updated to reflect
....@@ -355,19 +436,14 @@
355436 */
356437 static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
357438 {
358
- unsigned long *savep;
359439 struct rtas_error_log *h;
440
+ __be64 *savep;
360441
361
- /* Mask top two bits */
362
- regs->gpr[3] &= ~(0x3UL << 62);
363
-
364
- if (!VALID_FWNMI_BUFFER(regs->gpr[3])) {
365
- printk(KERN_ERR "FWNMI: corrupt r3 0x%016lx\n", regs->gpr[3]);
442
+ savep = fwnmi_get_savep(regs);
443
+ if (!savep)
366444 return NULL;
367
- }
368445
369
- savep = __va(regs->gpr[3]);
370
- regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
446
+ regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
371447
372448 h = (struct rtas_error_log *)&savep[1];
373449 /* Use the per cpu buffer from paca to store rtas error log */
....@@ -391,7 +467,15 @@
391467 */
392468 static void fwnmi_release_errinfo(void)
393469 {
394
- int ret = rtas_call(rtas_token("ibm,nmi-interlock"), 0, 1, NULL);
470
+ struct rtas_args rtas_args;
471
+ int ret;
472
+
473
+ /*
474
+ * On pseries, the machine check stack is limited to under 4GB, so
475
+ * args can be on-stack.
476
+ */
477
+ rtas_call_unlocked(&rtas_args, ibm_nmi_interlock_token, 0, 1, NULL);
478
+ ret = be32_to_cpu(rtas_args.rets[0]);
395479 if (ret != 0)
396480 printk(KERN_ERR "FWNMI: nmi-interlock failed: %d\n", ret);
397481 }
....@@ -414,17 +498,256 @@
414498 #endif
415499
416500 if (fwnmi_active) {
417
- struct rtas_error_log *errhdr = fwnmi_get_errinfo(regs);
418
- if (errhdr) {
419
- /* XXX Should look at FWNMI information */
420
- }
421
- fwnmi_release_errinfo();
501
+ __be64 *savep;
502
+
503
+ /*
504
+ * Firmware (PowerVM and KVM) saves r3 to a save area like
505
+ * machine check, which is not exactly what PAPR (2.9)
506
+ * suggests but there is no way to detect otherwise, so this
507
+ * is the interface now.
508
+ *
509
+ * System resets do not save any error log or require an
510
+ * "ibm,nmi-interlock" rtas call to release.
511
+ */
512
+
513
+ savep = fwnmi_get_savep(regs);
514
+ if (savep)
515
+ regs->gpr[3] = be64_to_cpu(savep[0]); /* restore original r3 */
422516 }
423517
424518 if (smp_handle_nmi_ipi(regs))
425519 return 1;
426520
427521 return 0; /* need to perform reset */
522
+}
523
+
524
+static int mce_handle_err_realmode(int disposition, u8 error_type)
525
+{
526
+#ifdef CONFIG_PPC_BOOK3S_64
527
+ if (disposition == RTAS_DISP_NOT_RECOVERED) {
528
+ switch (error_type) {
529
+ case MC_ERROR_TYPE_SLB:
530
+ case MC_ERROR_TYPE_ERAT:
531
+ /*
532
+ * Store the old slb content in paca before flushing.
533
+ * Print this when we go to virtual mode.
534
+ * There are chances that we may hit MCE again if there
535
+ * is a parity error on the SLB entry we trying to read
536
+ * for saving. Hence limit the slb saving to single
537
+ * level of recursion.
538
+ */
539
+ if (local_paca->in_mce == 1)
540
+ slb_save_contents(local_paca->mce_faulty_slbs);
541
+ flush_and_reload_slb();
542
+ disposition = RTAS_DISP_FULLY_RECOVERED;
543
+ break;
544
+ default:
545
+ break;
546
+ }
547
+ } else if (disposition == RTAS_DISP_LIMITED_RECOVERY) {
548
+ /* Platform corrected itself but could be degraded */
549
+ pr_err("MCE: limited recovery, system may be degraded\n");
550
+ disposition = RTAS_DISP_FULLY_RECOVERED;
551
+ }
552
+#endif
553
+ return disposition;
554
+}
555
+
556
+static int mce_handle_err_virtmode(struct pt_regs *regs,
557
+ struct rtas_error_log *errp,
558
+ struct pseries_mc_errorlog *mce_log,
559
+ int disposition)
560
+{
561
+ struct mce_error_info mce_err = { 0 };
562
+ int initiator = rtas_error_initiator(errp);
563
+ int severity = rtas_error_severity(errp);
564
+ unsigned long eaddr = 0, paddr = 0;
565
+ u8 error_type, err_sub_type;
566
+
567
+ if (!mce_log)
568
+ goto out;
569
+
570
+ error_type = mce_log->error_type;
571
+ err_sub_type = rtas_mc_error_sub_type(mce_log);
572
+
573
+ if (initiator == RTAS_INITIATOR_UNKNOWN)
574
+ mce_err.initiator = MCE_INITIATOR_UNKNOWN;
575
+ else if (initiator == RTAS_INITIATOR_CPU)
576
+ mce_err.initiator = MCE_INITIATOR_CPU;
577
+ else if (initiator == RTAS_INITIATOR_PCI)
578
+ mce_err.initiator = MCE_INITIATOR_PCI;
579
+ else if (initiator == RTAS_INITIATOR_ISA)
580
+ mce_err.initiator = MCE_INITIATOR_ISA;
581
+ else if (initiator == RTAS_INITIATOR_MEMORY)
582
+ mce_err.initiator = MCE_INITIATOR_MEMORY;
583
+ else if (initiator == RTAS_INITIATOR_POWERMGM)
584
+ mce_err.initiator = MCE_INITIATOR_POWERMGM;
585
+ else
586
+ mce_err.initiator = MCE_INITIATOR_UNKNOWN;
587
+
588
+ if (severity == RTAS_SEVERITY_NO_ERROR)
589
+ mce_err.severity = MCE_SEV_NO_ERROR;
590
+ else if (severity == RTAS_SEVERITY_EVENT)
591
+ mce_err.severity = MCE_SEV_WARNING;
592
+ else if (severity == RTAS_SEVERITY_WARNING)
593
+ mce_err.severity = MCE_SEV_WARNING;
594
+ else if (severity == RTAS_SEVERITY_ERROR_SYNC)
595
+ mce_err.severity = MCE_SEV_SEVERE;
596
+ else if (severity == RTAS_SEVERITY_ERROR)
597
+ mce_err.severity = MCE_SEV_SEVERE;
598
+ else if (severity == RTAS_SEVERITY_FATAL)
599
+ mce_err.severity = MCE_SEV_FATAL;
600
+ else
601
+ mce_err.severity = MCE_SEV_FATAL;
602
+
603
+ if (severity <= RTAS_SEVERITY_ERROR_SYNC)
604
+ mce_err.sync_error = true;
605
+ else
606
+ mce_err.sync_error = false;
607
+
608
+ mce_err.error_type = MCE_ERROR_TYPE_UNKNOWN;
609
+ mce_err.error_class = MCE_ECLASS_UNKNOWN;
610
+
611
+ switch (error_type) {
612
+ case MC_ERROR_TYPE_UE:
613
+ mce_err.error_type = MCE_ERROR_TYPE_UE;
614
+ mce_common_process_ue(regs, &mce_err);
615
+ if (mce_err.ignore_event)
616
+ disposition = RTAS_DISP_FULLY_RECOVERED;
617
+ switch (err_sub_type) {
618
+ case MC_ERROR_UE_IFETCH:
619
+ mce_err.u.ue_error_type = MCE_UE_ERROR_IFETCH;
620
+ break;
621
+ case MC_ERROR_UE_PAGE_TABLE_WALK_IFETCH:
622
+ mce_err.u.ue_error_type = MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH;
623
+ break;
624
+ case MC_ERROR_UE_LOAD_STORE:
625
+ mce_err.u.ue_error_type = MCE_UE_ERROR_LOAD_STORE;
626
+ break;
627
+ case MC_ERROR_UE_PAGE_TABLE_WALK_LOAD_STORE:
628
+ mce_err.u.ue_error_type = MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE;
629
+ break;
630
+ case MC_ERROR_UE_INDETERMINATE:
631
+ default:
632
+ mce_err.u.ue_error_type = MCE_UE_ERROR_INDETERMINATE;
633
+ break;
634
+ }
635
+ if (mce_log->sub_err_type & UE_EFFECTIVE_ADDR_PROVIDED)
636
+ eaddr = be64_to_cpu(mce_log->effective_address);
637
+
638
+ if (mce_log->sub_err_type & UE_LOGICAL_ADDR_PROVIDED) {
639
+ paddr = be64_to_cpu(mce_log->logical_address);
640
+ } else if (mce_log->sub_err_type & UE_EFFECTIVE_ADDR_PROVIDED) {
641
+ unsigned long pfn;
642
+
643
+ pfn = addr_to_pfn(regs, eaddr);
644
+ if (pfn != ULONG_MAX)
645
+ paddr = pfn << PAGE_SHIFT;
646
+ }
647
+
648
+ break;
649
+ case MC_ERROR_TYPE_SLB:
650
+ mce_err.error_type = MCE_ERROR_TYPE_SLB;
651
+ switch (err_sub_type) {
652
+ case MC_ERROR_SLB_PARITY:
653
+ mce_err.u.slb_error_type = MCE_SLB_ERROR_PARITY;
654
+ break;
655
+ case MC_ERROR_SLB_MULTIHIT:
656
+ mce_err.u.slb_error_type = MCE_SLB_ERROR_MULTIHIT;
657
+ break;
658
+ case MC_ERROR_SLB_INDETERMINATE:
659
+ default:
660
+ mce_err.u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE;
661
+ break;
662
+ }
663
+ if (mce_log->sub_err_type & 0x80)
664
+ eaddr = be64_to_cpu(mce_log->effective_address);
665
+ break;
666
+ case MC_ERROR_TYPE_ERAT:
667
+ mce_err.error_type = MCE_ERROR_TYPE_ERAT;
668
+ switch (err_sub_type) {
669
+ case MC_ERROR_ERAT_PARITY:
670
+ mce_err.u.erat_error_type = MCE_ERAT_ERROR_PARITY;
671
+ break;
672
+ case MC_ERROR_ERAT_MULTIHIT:
673
+ mce_err.u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
674
+ break;
675
+ case MC_ERROR_ERAT_INDETERMINATE:
676
+ default:
677
+ mce_err.u.erat_error_type = MCE_ERAT_ERROR_INDETERMINATE;
678
+ break;
679
+ }
680
+ if (mce_log->sub_err_type & 0x80)
681
+ eaddr = be64_to_cpu(mce_log->effective_address);
682
+ break;
683
+ case MC_ERROR_TYPE_TLB:
684
+ mce_err.error_type = MCE_ERROR_TYPE_TLB;
685
+ switch (err_sub_type) {
686
+ case MC_ERROR_TLB_PARITY:
687
+ mce_err.u.tlb_error_type = MCE_TLB_ERROR_PARITY;
688
+ break;
689
+ case MC_ERROR_TLB_MULTIHIT:
690
+ mce_err.u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT;
691
+ break;
692
+ case MC_ERROR_TLB_INDETERMINATE:
693
+ default:
694
+ mce_err.u.tlb_error_type = MCE_TLB_ERROR_INDETERMINATE;
695
+ break;
696
+ }
697
+ if (mce_log->sub_err_type & 0x80)
698
+ eaddr = be64_to_cpu(mce_log->effective_address);
699
+ break;
700
+ case MC_ERROR_TYPE_D_CACHE:
701
+ mce_err.error_type = MCE_ERROR_TYPE_DCACHE;
702
+ break;
703
+ case MC_ERROR_TYPE_I_CACHE:
704
+ mce_err.error_type = MCE_ERROR_TYPE_DCACHE;
705
+ break;
706
+ case MC_ERROR_TYPE_UNKNOWN:
707
+ default:
708
+ mce_err.error_type = MCE_ERROR_TYPE_UNKNOWN;
709
+ break;
710
+ }
711
+out:
712
+ save_mce_event(regs, disposition == RTAS_DISP_FULLY_RECOVERED,
713
+ &mce_err, regs->nip, eaddr, paddr);
714
+ return disposition;
715
+}
716
+
717
+static int mce_handle_error(struct pt_regs *regs, struct rtas_error_log *errp)
718
+{
719
+ struct pseries_errorlog *pseries_log;
720
+ struct pseries_mc_errorlog *mce_log = NULL;
721
+ int disposition = rtas_error_disposition(errp);
722
+ u8 error_type;
723
+
724
+ if (!rtas_error_extended(errp))
725
+ goto out;
726
+
727
+ pseries_log = get_pseries_errorlog(errp, PSERIES_ELOG_SECT_ID_MCE);
728
+ if (!pseries_log)
729
+ goto out;
730
+
731
+ mce_log = (struct pseries_mc_errorlog *)pseries_log->data;
732
+ error_type = mce_log->error_type;
733
+
734
+ disposition = mce_handle_err_realmode(disposition, error_type);
735
+
736
+ /*
737
+ * Enable translation as we will be accessing per-cpu variables
738
+ * in save_mce_event() which may fall outside RMO region, also
739
+ * leave it enabled because subsequently we will be queuing work
740
+ * to workqueues where again per-cpu variables accessed, besides
741
+ * fwnmi_release_errinfo() crashes when called in realmode on
742
+ * pseries.
743
+ * Note: All the realmode handling like flushing SLB entries for
744
+ * SLB multihit is done by now.
745
+ */
746
+out:
747
+ mtmsr(mfmsr() | MSR_IR | MSR_DR);
748
+ disposition = mce_handle_err_virtmode(regs, errp, mce_log,
749
+ disposition);
750
+ return disposition;
428751 }
429752
430753 /*
....@@ -447,43 +770,50 @@
447770 * Return 1 if corrected (or delivered a signal).
448771 * Return 0 if there is nothing we can do.
449772 */
450
-static int recover_mce(struct pt_regs *regs, struct rtas_error_log *err)
773
+static int recover_mce(struct pt_regs *regs, struct machine_check_event *evt)
451774 {
452775 int recovered = 0;
453
- int disposition = rtas_error_disposition(err);
454776
455777 if (!(regs->msr & MSR_RI)) {
456778 /* If MSR_RI isn't set, we cannot recover */
779
+ pr_err("Machine check interrupt unrecoverable: MSR(RI=0)\n");
457780 recovered = 0;
458
-
459
- } else if (disposition == RTAS_DISP_FULLY_RECOVERED) {
781
+ } else if (evt->disposition == MCE_DISPOSITION_RECOVERED) {
460782 /* Platform corrected itself */
461783 recovered = 1;
462
-
463
- } else if (disposition == RTAS_DISP_LIMITED_RECOVERY) {
464
- /* Platform corrected itself but could be degraded */
465
- printk(KERN_ERR "MCE: limited recovery, system may "
466
- "be degraded\n");
467
- recovered = 1;
468
-
469
- } else if (user_mode(regs) && !is_global_init(current) &&
470
- rtas_error_severity(err) == RTAS_SEVERITY_ERROR_SYNC) {
471
-
472
- /*
473
- * If we received a synchronous error when in userspace
474
- * kill the task. Firmware may report details of the fail
475
- * asynchronously, so we can't rely on the target and type
476
- * fields being valid here.
477
- */
478
- printk(KERN_ERR "MCE: uncorrectable error, killing task "
479
- "%s:%d\n", current->comm, current->pid);
480
-
481
- _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
482
- recovered = 1;
784
+ } else if (evt->severity == MCE_SEV_FATAL) {
785
+ /* Fatal machine check */
786
+ pr_err("Machine check interrupt is fatal\n");
787
+ recovered = 0;
483788 }
484789
485
- /* Queue irq work to log this rtas event later. */
486
- irq_work_queue(&mce_errlog_process_work);
790
+ if (!recovered && evt->sync_error) {
791
+ /*
792
+ * Try to kill processes if we get a synchronous machine check
793
+ * (e.g., one caused by execution of this instruction). This
794
+ * will devolve into a panic if we try to kill init or are in
795
+ * an interrupt etc.
796
+ *
797
+ * TODO: Queue up this address for hwpoisioning later.
798
+ * TODO: This is not quite right for d-side machine
799
+ * checks ->nip is not necessarily the important
800
+ * address.
801
+ */
802
+ if ((user_mode(regs))) {
803
+ _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
804
+ recovered = 1;
805
+ } else if (die_will_crash()) {
806
+ /*
807
+ * die() would kill the kernel, so better to go via
808
+ * the platform reboot code that will log the
809
+ * machine check.
810
+ */
811
+ recovered = 0;
812
+ } else {
813
+ die("Machine check", regs, SIGBUS);
814
+ recovered = 1;
815
+ }
816
+ }
487817
488818 return recovered;
489819 }
....@@ -500,12 +830,44 @@
500830 */
501831 int pSeries_machine_check_exception(struct pt_regs *regs)
502832 {
833
+ struct machine_check_event evt;
834
+
835
+ if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
836
+ return 0;
837
+
838
+ /* Print things out */
839
+ if (evt.version != MCE_V1) {
840
+ pr_err("Machine Check Exception, Unknown event version %d !\n",
841
+ evt.version);
842
+ return 0;
843
+ }
844
+ machine_check_print_event_info(&evt, user_mode(regs), false);
845
+
846
+ if (recover_mce(regs, &evt))
847
+ return 1;
848
+
849
+ return 0;
850
+}
851
+
852
+long pseries_machine_check_realmode(struct pt_regs *regs)
853
+{
503854 struct rtas_error_log *errp;
855
+ int disposition;
504856
505857 if (fwnmi_active) {
506858 errp = fwnmi_get_errinfo(regs);
859
+ /*
860
+ * Call to fwnmi_release_errinfo() in real mode causes kernel
861
+ * to panic. Hence we will call it as soon as we go into
862
+ * virtual mode.
863
+ */
864
+ disposition = mce_handle_error(regs, errp);
507865 fwnmi_release_errinfo();
508
- if (errp && recover_mce(regs, errp))
866
+
867
+ /* Queue irq work to log this rtas event later. */
868
+ irq_work_queue(&mce_errlog_process_work);
869
+
870
+ if (disposition == RTAS_DISP_FULLY_RECOVERED)
509871 return 1;
510872 }
511873