Commit 895e3dce authored by Balbir Singh's avatar Balbir Singh Committed by Michael Ellerman

powerpc/mce: Handle UE event for memcpy_mcsafe

If we take a UE on one of the instructions with a fixup entry, set nip
to continue execution at the fixup entry. Stop processing the event
further or print it.
Co-developed-by: default avatarReza Arbab <arbab@linux.ibm.com>
Signed-off-by: default avatarReza Arbab <arbab@linux.ibm.com>
Signed-off-by: default avatarBalbir Singh <bsingharora@gmail.com>
Reviewed-by: default avatarMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Reviewed-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarSantosh Sivaraj <santosh@fossix.org>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20190820081352.8641-6-santosh@fossix.org
parent 49ec9177
...@@ -122,7 +122,8 @@ struct machine_check_event { ...@@ -122,7 +122,8 @@ struct machine_check_event {
enum MCE_UeErrorType ue_error_type:8; enum MCE_UeErrorType ue_error_type:8;
u8 effective_address_provided; u8 effective_address_provided;
u8 physical_address_provided; u8 physical_address_provided;
u8 reserved_1[5]; u8 ignore_event;
u8 reserved_1[4];
u64 effective_address; u64 effective_address;
u64 physical_address; u64 physical_address;
u8 reserved_2[8]; u8 reserved_2[8];
...@@ -193,6 +194,7 @@ struct mce_error_info { ...@@ -193,6 +194,7 @@ struct mce_error_info {
enum MCE_Initiator initiator:8; enum MCE_Initiator initiator:8;
enum MCE_ErrorClass error_class:8; enum MCE_ErrorClass error_class:8;
bool sync_error; bool sync_error;
bool ignore_event;
}; };
#define MAX_MC_EVT 100 #define MAX_MC_EVT 100
......
...@@ -149,6 +149,7 @@ void save_mce_event(struct pt_regs *regs, long handled, ...@@ -149,6 +149,7 @@ void save_mce_event(struct pt_regs *regs, long handled,
if (phys_addr != ULONG_MAX) { if (phys_addr != ULONG_MAX) {
mce->u.ue_error.physical_address_provided = true; mce->u.ue_error.physical_address_provided = true;
mce->u.ue_error.physical_address = phys_addr; mce->u.ue_error.physical_address = phys_addr;
mce->u.ue_error.ignore_event = mce_err->ignore_event;
machine_check_ue_event(mce); machine_check_ue_event(mce);
} }
} }
...@@ -266,8 +267,17 @@ static void machine_process_ue_event(struct work_struct *work) ...@@ -266,8 +267,17 @@ static void machine_process_ue_event(struct work_struct *work)
/* /*
* This should probably queued elsewhere, but * This should probably queued elsewhere, but
* oh! well * oh! well
*
* Don't report this machine check because the caller has a
* asked us to ignore the event, it has a fixup handler which
* will do the appropriate error handling and reporting.
*/ */
if (evt->error_type == MCE_ERROR_TYPE_UE) { if (evt->error_type == MCE_ERROR_TYPE_UE) {
if (evt->u.ue_error.ignore_event) {
__this_cpu_dec(mce_ue_count);
continue;
}
if (evt->u.ue_error.physical_address_provided) { if (evt->u.ue_error.physical_address_provided) {
unsigned long pfn; unsigned long pfn;
...@@ -301,6 +311,12 @@ static void machine_check_process_queued_event(struct irq_work *work) ...@@ -301,6 +311,12 @@ static void machine_check_process_queued_event(struct irq_work *work)
while (__this_cpu_read(mce_queue_count) > 0) { while (__this_cpu_read(mce_queue_count) > 0) {
index = __this_cpu_read(mce_queue_count) - 1; index = __this_cpu_read(mce_queue_count) - 1;
evt = this_cpu_ptr(&mce_event_queue[index]); evt = this_cpu_ptr(&mce_event_queue[index]);
if (evt->error_type == MCE_ERROR_TYPE_UE &&
evt->u.ue_error.ignore_event) {
__this_cpu_dec(mce_queue_count);
continue;
}
machine_check_print_event_info(evt, false, false); machine_check_print_event_info(evt, false, false);
__this_cpu_dec(mce_queue_count); __this_cpu_dec(mce_queue_count);
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/extable.h>
#include <asm/mmu.h> #include <asm/mmu.h>
#include <asm/mce.h> #include <asm/mce.h>
#include <asm/machdep.h> #include <asm/machdep.h>
...@@ -18,6 +19,7 @@ ...@@ -18,6 +19,7 @@
#include <asm/pte-walk.h> #include <asm/pte-walk.h>
#include <asm/sstep.h> #include <asm/sstep.h>
#include <asm/exception-64s.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 * 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, ...@@ -565,9 +567,18 @@ static int mce_handle_derror(struct pt_regs *regs,
return 0; 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; long handled = 0;
const struct exception_table_entry *entry;
entry = search_kernel_exception_table(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 * 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, ...@@ -600,7 +611,7 @@ static long mce_handle_error(struct pt_regs *regs,
&phys_addr); &phys_addr);
if (!handled && mce_err.error_type == MCE_ERROR_TYPE_UE) 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); save_mce_event(regs, handled, &mce_err, regs->nip, addr, phys_addr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment