If we take a UE on one of the instructions with a fixup entry, set nip
to continue exucution at the fixup entry. Stop processing the event
further or print it.

Based-on-patch-by: Reza Arbab <ar...@linux.ibm.com>
Cc: Reza Arbab <ar...@linux.ibm.com>
Cc: Mahesh Salgaonkar <mah...@linux.ibm.com>
Signed-off-by: Santosh Sivaraj <sant...@fossix.org>
---
 arch/powerpc/include/asm/mce.h  |  4 +++-
 arch/powerpc/kernel/mce.c       |  7 ++++++-
 arch/powerpc/kernel/mce_power.c | 15 +++++++++++++--
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
index 94888a7025b3..f74257eb013b 100644
--- a/arch/powerpc/include/asm/mce.h
+++ b/arch/powerpc/include/asm/mce.h
@@ -122,7 +122,8 @@ struct machine_check_event {
                        enum MCE_UeErrorType ue_error_type:8;
                        u8              effective_address_provided;
                        u8              physical_address_provided;
-                       u8              reserved_1[5];
+                       u8              ignore_event;
+                       u8              reserved_1[4];
                        u64             effective_address;
                        u64             physical_address;
                        u8              reserved_2[8];
@@ -193,6 +194,7 @@ struct mce_error_info {
        enum MCE_Initiator      initiator:8;
        enum MCE_ErrorClass     error_class:8;
        bool                    sync_error;
+       bool                    ignore_event;
 };
 
 #define MAX_MC_EVT     100
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
index e78c4f18ea0a..94f2bb307537 100644
--- a/arch/powerpc/kernel/mce.c
+++ b/arch/powerpc/kernel/mce.c
@@ -144,7 +144,9 @@ void save_mce_event(struct pt_regs *regs, long handled,
                if (phys_addr != ULONG_MAX) {
                        mce->u.ue_error.physical_address_provided = true;
                        mce->u.ue_error.physical_address = phys_addr;
-                       machine_check_ue_event(mce);
+                       mce->u.ue_error.ignore_event = mce_err->ignore_event;
+                       if (!mce->u.ue_error.ignore_event)
+                               machine_check_ue_event(mce);
                }
        }
        return;
@@ -230,6 +232,9 @@ void machine_check_queue_event(void)
        if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
                return;
 
+       if (evt.error_type == MCE_ERROR_TYPE_UE && evt.u.ue_error.ignore_event)
+               return;
+
        index = __this_cpu_inc_return(mce_queue_count) - 1;
        /* If queue is full, just return for now. */
        if (index >= MAX_MC_EVT) {
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
index 04666c0b40a8..db4aa98a23ac 100644
--- a/arch/powerpc/kernel/mce_power.c
+++ b/arch/powerpc/kernel/mce_power.c
@@ -11,6 +11,7 @@
 
 #include <linux/types.h>
 #include <linux/ptrace.h>
+#include <linux/extable.h>
 #include <asm/mmu.h>
 #include <asm/mce.h>
 #include <asm/machdep.h>
@@ -18,6 +19,7 @@
 #include <asm/pte-walk.h>
 #include <asm/sstep.h>
 #include <asm/exception-64s.h>
+#include <asm/extable.h>
 
 /*
  * Convert an address related to an mm to a PFN. NOTE: we are in real
@@ -565,9 +567,18 @@ static int mce_handle_derror(struct pt_regs *regs,
        return 0;
 }
 
-static long mce_handle_ue_error(struct pt_regs *regs)
+static long mce_handle_ue_error(struct pt_regs *regs,
+                               struct mce_error_info *mce_err)
 {
        long handled = 0;
+       const struct exception_table_entry *entry;
+
+       entry = search_exception_tables(regs->nip);
+       if (entry) {
+               mce_err->ignore_event = true;
+               regs->nip = extable_fixup(entry);
+               return 1;
+       }
 
        /*
         * On specific SCOM read via MMIO we may get a machine check
@@ -600,7 +611,7 @@ static long mce_handle_error(struct pt_regs *regs,
                                &phys_addr);
 
        if (!handled && mce_err.error_type == MCE_ERROR_TYPE_UE)
-               handled = mce_handle_ue_error(regs);
+               handled = mce_handle_ue_error(regs, &mce_err);
 
        save_mce_event(regs, handled, &mce_err, regs->nip, addr, phys_addr);
 
-- 
2.20.1

Reply via email to