table-based machine check handlers
Nicholas Piggin
reviewercover table-based machine check handlers
Hi,
This is a rebase of the table based MCE patches on top of the POWER9 handler that was merged upstream. Plus a couple of misc things (patches 1 and 6).
The plan is to have OPAL firmware do most of this recovery and parsing in future, but I think it's worth tidying this up. IMO it's easier to see what's going on and less error prone to change or add things.
Thanks,
Nick
Nicholas Piggin (6):
powerpc/64s: machine check print NIP
powerpc/64s: clean up machine check recovery flushing powerpc/64s: move POWER machine check defines into mce_power.c powerpc/64s: data driven machine check evaluation powerpc/64s: data driven machine check handling powerpc/64s: POWER8 add missing machine check definitions
arch/powerpc/include/asm/mce.h | 91 ----- arch/powerpc/kernel/mce.c | 3 +- arch/powerpc/kernel/mce_power.c | 776 +++++++++++++++++++--------------------- 3 files changed, 369 insertions(+), 501 deletions(-)
Signature · 1 line
2.11.0
Nicholas Piggin
reviewerPATCH 1/6 powerpc/64s: machine check print NIP
Print the faulting address of the machine check that may help with debugging. The effective address reported can be a target memory address rather than the faulting instruction address.
Fix up a dangling bracket while here.
--- arch/powerpc/kernel/mce.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/powerpc/kernel/mce.c +2 -1
@@ -310,7 +310,8 @@ void machine_check_print_event_info(struct machine_check_event *evt)printk ("%s%s Machine check interrupt [%s]\n" , level, sevstr, evt->disposition ==MCE_DISPOSITION_RECOVERED ? -"Recovered" :"[Not recovered" ); +"Recovered" :"Not recovered" ); +printk ("%s NIP: %016llx\n" , level, evt->srr0);printk ("%s Initiator: %s\n" , level, evt->initiator ==MCE_INITIATOR_CPU ?"CPU" :"Unknown" );switch (evt->error_type) {
Signature · 1 line
2.11.0
Re: [1/6] powerpc/64s: machine check print NIP
Quoted 7 lines · Nicholas Piggin
Print the faulting address of the machine check that may help with debugging. The effective address reported can be a target memory address rather than the faulting instruction address.
Fix up a dangling bracket while here.
Signed-off-by Nicholas Piggin <[email protected]>
Series applied to powerpc next, thanks.
https://git.kernel.org/powerpc/c/fc84427b7e1471b0a1220c56072f57
cheers
Nicholas Piggin
reviewerPATCH 2/6 powerpc/64s: clean up machine check recovery flushing
In reply to Nicholas PigginUse the flush function introduced with the POWER9 machine check handler for POWER7 and 8, rather than open coding it multiple times in callers.
There is a specific ERAT flush type introduced for POWER9, but the POWER7-8 ERAT errors continue to do SLB flushing (which also flushes ERAT), so as not to introduce functional changes with this cleanup patch.
--- arch/powerpc/kernel/mce_power.c | 97 ++++++++++------------------------------- 1 file changed, 23 insertions(+), 74 deletions(-)
arch/powerpc/kernel/mce_power.c +23 -74
@@ -161,81 +161,27 @@ static int mce_handle_flush_derrors(uint64_t dsisr, uint64_t slb, uint64_t tlb,return 1 ; } -static long mce_handle_derror (uint64_t dsisr,uint64_t slb_error_bits) -{ -long handled =1 ; - -/* -* flush and reload SLBs for SLB errors and flush TLBs for TLB errors. -* reset the error bits whenever we handle them so that at the end -* we can check whether we handled all of them or not. -* */ -#ifdef CONFIG_PPC_STD_MMU_64 -if (dsisr & slb_error_bits) { -flush_and_reload_slb (); -/* reset error bits */ - dsisr &= ~(slb_error_bits); - } -if (dsisr &P7_DSISR_MC_TLB_MULTIHIT_MFTLB ) { -if (cur_cpu_spec && cur_cpu_spec->flush_tlb) - cur_cpu_spec->flush_tlb (TLB_INVAL_SCOPE_GLOBAL ); -/* reset error bits */ - dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB ; - } -#endif -/* Any other errors we don't understand? */ -if (dsisr &0xffffffffUL ) - handled =0 ; - -return handled; -} -static long mce_handle_derror_p7 (uint64_t dsisr) { -return mce_handle_derror (dsisr,P7_DSISR_MC_SLB_ERRORS ); +return mce_handle_flush_derrors (dsisr, +P7_DSISR_MC_SLB_ERRORS , +P7_DSISR_MC_TLB_MULTIHIT_MFTLB , +0 ); } -static long mce_handle_common_ierror (uint64_t srr1) +static long mce_handle_ierror_p7 (uint64_t srr1) { -long handled =0 ; -switch (P7_SRR1_MC_IFETCH (srr1)) { -case 0 : -break ; -#ifdef CONFIG_PPC_STD_MMU_64 case P7_SRR1_MC_IFETCH_SLB_PARITY :case P7_SRR1_MC_IFETCH_SLB_MULTIHIT : -/* flush and reload SLBs for SLB errors. */ -flush_and_reload_slb (); - handled =1 ; -break ; +case P7_SRR1_MC_IFETCH_SLB_BOTH : +return mce_flush (MCE_FLUSH_SLB ); +case P7_SRR1_MC_IFETCH_TLB_MULTIHIT : -if (cur_cpu_spec && cur_cpu_spec->flush_tlb) { - cur_cpu_spec->flush_tlb (TLB_INVAL_SCOPE_GLOBAL ); - handled =1 ; - } -break ; -#endif +return mce_flush (MCE_FLUSH_TLB );default : -break ; - } - -return handled; -} - -static long mce_handle_ierror_p7 (uint64_t srr1) -{ -long handled =0 ; - - handled =mce_handle_common_ierror (srr1); - -#ifdef CONFIG_PPC_STD_MMU_64 -if (P7_SRR1_MC_IFETCH (srr1) ==P7_SRR1_MC_IFETCH_SLB_BOTH ) { -flush_and_reload_slb (); - handled =1 ; +return 0 ; } -#endif -return handled; }static void mce_get_common_ierror (struct mce_error_info *mce_err,uint64_t srr1)
@@ -376,22 +322,25 @@ static void mce_get_derror_p8(struct mce_error_info *mce_err, uint64_t dsisr)static long mce_handle_ierror_p8 (uint64_t srr1) { -long handled =0 ; - - handled =mce_handle_common_ierror (srr1); +switch (P7_SRR1_MC_IFETCH (srr1)) { +case P7_SRR1_MC_IFETCH_SLB_PARITY : +case P7_SRR1_MC_IFETCH_SLB_MULTIHIT : +case P8_SRR1_MC_IFETCH_ERAT_MULTIHIT : +return mce_flush (MCE_FLUSH_SLB ); -#ifdef CONFIG_PPC_STD_MMU_64 -if (P7_SRR1_MC_IFETCH (srr1) ==P8_SRR1_MC_IFETCH_ERAT_MULTIHIT ) { -flush_and_reload_slb (); - handled =1 ; +case P7_SRR1_MC_IFETCH_TLB_MULTIHIT : +return mce_flush (MCE_FLUSH_TLB ); +default : +return 0 ; } -#endif -return handled; }static long mce_handle_derror_p8 (uint64_t dsisr) { -return mce_handle_derror (dsisr,P8_DSISR_MC_SLB_ERRORS ); +return mce_handle_flush_derrors (dsisr, +P8_DSISR_MC_SLB_ERRORS , +P7_DSISR_MC_TLB_MULTIHIT_MFTLB , +0 ); }long __machine_check_early_realmode_p8 (struct pt_regs *regs)
Signature · 1 line
2.11.0
Nicholas Piggin
reviewerPATCH 3/6 powerpc/64s: move POWER machine check defines into mce_power.c
In reply to Nicholas Piggin--- arch/powerpc/include/asm/mce.h | 91 ---------------------------------------- arch/powerpc/kernel/mce_power.c | 92 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 91 deletions(-)
arch/powerpc/include/asm/mce.h +0 -91
@@ -24,97 +24,6 @@#include <linux/bitops.h> -/* -* Machine Check bits on power7 and power8 -*/ -#define P7_SRR1_MC_LOADSTORE (srr1) ((srr1) & PPC_BIT(42))/* P8 too */ - -/* SRR1 bits for machine check (On Power7 and Power8) */ -#define P7_SRR1_MC_IFETCH (srr1) ((srr1) & PPC_BITMASK(43, 45))/* P8 too */ - -#define P7_SRR1_MC_IFETCH_UE (0x1 << PPC_BITLSHIFT(45))/* P8 too */ -#define P7_SRR1_MC_IFETCH_SLB_PARITY (0x2 << PPC_BITLSHIFT(45))/* P8 too */ -#define P7_SRR1_MC_IFETCH_SLB_MULTIHIT (0x3 << PPC_BITLSHIFT(45))/* P8 too */ -#define P7_SRR1_MC_IFETCH_SLB_BOTH (0x4 << PPC_BITLSHIFT(45)) -#define P7_SRR1_MC_IFETCH_TLB_MULTIHIT (0x5 << PPC_BITLSHIFT(45))/* P8 too */ -#define P7_SRR1_MC_IFETCH_UE_TLB_RELOAD (0x6 << PPC_BITLSHIFT(45))/* P8 too */ -#define P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL (0x7 << PPC_BITLSHIFT(45)) - -/* SRR1 bits for machine check (On Power8) */ -#define P8_SRR1_MC_IFETCH_ERAT_MULTIHIT (0x4 << PPC_BITLSHIFT(45)) - -/* DSISR bits for machine check (On Power7 and Power8) */ -#define P7_DSISR_MC_UE (PPC_BIT(48))/* P8 too */ -#define P7_DSISR_MC_UE_TABLEWALK (PPC_BIT(49))/* P8 too */ -#define P7_DSISR_MC_ERAT_MULTIHIT (PPC_BIT(52))/* P8 too */ -#define P7_DSISR_MC_TLB_MULTIHIT_MFTLB (PPC_BIT(53))/* P8 too */ -#define P7_DSISR_MC_SLB_PARITY_MFSLB (PPC_BIT(55))/* P8 too */ -#define P7_DSISR_MC_SLB_MULTIHIT (PPC_BIT(56))/* P8 too */ -#define P7_DSISR_MC_SLB_MULTIHIT_PARITY (PPC_BIT(57))/* P8 too */ - -/* -* DSISR bits for machine check (Power8) in addition to above. -* Secondary DERAT Multihit -*/ -#define P8_DSISR_MC_ERAT_MULTIHIT_SEC (PPC_BIT(54)) - -/* SLB error bits */ -#define P7_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_ERAT_MULTIHIT | \ - P7_DSISR_MC_SLB_PARITY_MFSLB | \ - P7_DSISR_MC_SLB_MULTIHIT | \ - P7_DSISR_MC_SLB_MULTIHIT_PARITY) - -#define P8_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_SLB_ERRORS | \ - P8_DSISR_MC_ERAT_MULTIHIT_SEC) - -/* -* Machine Check bits on power9 -*/ -#define P9_SRR1_MC_LOADSTORE (srr1) (((srr1) >> PPC_BITLSHIFT(42)) & 1) - -#define P9_SRR1_MC_IFETCH (srr1) ( \ - PPC_BITEXTRACT(srr1, 45, 0) | \ - PPC_BITEXTRACT(srr1, 44, 1) | \ - PPC_BITEXTRACT(srr1, 43, 2) | \ - PPC_BITEXTRACT(srr1, 36, 3) ) - -/* 0 is reserved */ -#define P9_SRR1_MC_IFETCH_UE 1 -#define P9_SRR1_MC_IFETCH_SLB_PARITY 2 -#define P9_SRR1_MC_IFETCH_SLB_MULTIHIT 3 -#define P9_SRR1_MC_IFETCH_ERAT_MULTIHIT 4 -#define P9_SRR1_MC_IFETCH_TLB_MULTIHIT 5 -#define P9_SRR1_MC_IFETCH_UE_TLB_RELOAD 6 -/* 7 is reserved */ -#define P9_SRR1_MC_IFETCH_LINK_TIMEOUT 8 -#define P9_SRR1_MC_IFETCH_LINK_TABLEWALK_TIMEOUT 9 -/* 10 ? */ -#define P9_SRR1_MC_IFETCH_RA 11 -#define P9_SRR1_MC_IFETCH_RA_TABLEWALK 12 -#define P9_SRR1_MC_IFETCH_RA_ASYNC_STORE 13 -#define P9_SRR1_MC_IFETCH_LINK_ASYNC_STORE_TIMEOUT 14 -#define P9_SRR1_MC_IFETCH_RA_TABLEWALK_FOREIGN 15 - -/* DSISR bits for machine check (On Power9) */ -#define P9_DSISR_MC_UE (PPC_BIT(48)) -#define P9_DSISR_MC_UE_TABLEWALK (PPC_BIT(49)) -#define P9_DSISR_MC_LINK_LOAD_TIMEOUT (PPC_BIT(50)) -#define P9_DSISR_MC_LINK_TABLEWALK_TIMEOUT (PPC_BIT(51)) -#define P9_DSISR_MC_ERAT_MULTIHIT (PPC_BIT(52)) -#define P9_DSISR_MC_TLB_MULTIHIT_MFTLB (PPC_BIT(53)) -#define P9_DSISR_MC_USER_TLBIE (PPC_BIT(54)) -#define P9_DSISR_MC_SLB_PARITY_MFSLB (PPC_BIT(55)) -#define P9_DSISR_MC_SLB_MULTIHIT_MFSLB (PPC_BIT(56)) -#define P9_DSISR_MC_RA_LOAD (PPC_BIT(57)) -#define P9_DSISR_MC_RA_TABLEWALK (PPC_BIT(58)) -#define P9_DSISR_MC_RA_TABLEWALK_FOREIGN (PPC_BIT(59)) -#define P9_DSISR_MC_RA_FOREIGN (PPC_BIT(60)) - -/* SLB error bits */ -#define P9_DSISR_MC_SLB_ERRORS (P9_DSISR_MC_ERAT_MULTIHIT | \ - P9_DSISR_MC_SLB_PARITY_MFSLB | \ - P9_DSISR_MC_SLB_MULTIHIT_MFSLB) -enum MCE_Version {MCE_V1 =1 , };
arch/powerpc/kernel/mce_power.c +92 -0
98 lines not on this page · raw message
Signature · 1 line
2.11.0
Nicholas Piggin
reviewerPATCH 4/6 powerpc/64s: data driven machine check evaluation
In reply to Nicholas PigginHave machine types define i-side and d-side tables to describe their machine check encodings, and match entries to evaluate (for reporting) machine checks.
Functionality is mostly unchanged (tested with a userspace harness), but it does make a change in that it no longer records DAR as the effective address for those errors where it is specified to be invalid (which is a reporting change only).
--- arch/powerpc/kernel/mce_power.c | 571 +++++++++++++++++++++++----------------- 1 file changed, 328 insertions(+), 243 deletions(-)
arch/powerpc/kernel/mce_power.c +328 -243
@@ -253,91 +253,304 @@ static int mce_handle_flush_derrors(uint64_t dsisr, uint64_t slb, uint64_t tlb, P9_DSISR_MC_SLB_PARITY_MFSLB | \ P9_DSISR_MC_SLB_MULTIHIT_MFSLB) -static long mce_handle_derror_p7 (uint64_t dsisr) -{ -return mce_handle_flush_derrors (dsisr, -P7_DSISR_MC_SLB_ERRORS , -P7_DSISR_MC_TLB_MULTIHIT_MFTLB , -0 ); -} - -static long mce_handle_ierror_p7 (uint64_t srr1) +struct mce_ierror_table { +unsigned long srr1_mask; +unsigned long srr1_value; +bool nip_valid;/* nip is a valid indicator of faulting address */ +unsigned int error_type; +unsigned int error_subtype; +unsigned int initiator; +unsigned int severity; +}; + +static const struct mce_ierror_table mce_p7_ierror_table[] = { +{0x00000000001c0000 ,0x0000000000040000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_IFETCH , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x0000000000080000 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_PARITY , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x00000000000c0000 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x0000000000100000 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_INDETERMINATE ,/* BOTH */ +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x0000000000140000 , true, +MCE_ERROR_TYPE_TLB ,MCE_TLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x0000000000180000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x00000000001c0000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_IFETCH , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0 ,0 ,0 ,0 ,0 ,0 } }; + +static const struct mce_ierror_table mce_p8_ierror_table[] = { +{0x00000000001c0000 ,0x0000000000040000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_IFETCH , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x0000000000080000 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_PARITY , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x00000000000c0000 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x0000000000100000 , true, +MCE_ERROR_TYPE_ERAT ,MCE_ERAT_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x0000000000140000 , true, +MCE_ERROR_TYPE_TLB ,MCE_TLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x0000000000180000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000001c0000 ,0x00000000001c0000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_IFETCH , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0 ,0 ,0 ,0 ,0 ,0 } }; + +static const struct mce_ierror_table mce_p9_ierror_table[] = { +{0x00000000081c0000 ,0x0000000000040000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_IFETCH , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x0000000000080000 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_PARITY , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x00000000000c0000 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x0000000000100000 , true, +MCE_ERROR_TYPE_ERAT ,MCE_ERAT_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x0000000000140000 , true, +MCE_ERROR_TYPE_TLB ,MCE_TLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x0000000000180000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x0000000008000000 , true, +MCE_ERROR_TYPE_LINK ,MCE_LINK_ERROR_IFETCH_TIMEOUT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x0000000008040000 , true, +MCE_ERROR_TYPE_LINK ,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x00000000080c0000 , true, +MCE_ERROR_TYPE_RA ,MCE_RA_ERROR_IFETCH , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x0000000008100000 , true, +MCE_ERROR_TYPE_RA ,MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x0000000008140000 , false, +MCE_ERROR_TYPE_RA ,MCE_RA_ERROR_STORE , +MCE_INITIATOR_CPU ,MCE_SEV_FATAL , },/* ASYNC is fatal */ +{0x00000000081c0000 ,0x0000000008180000 , false, +MCE_ERROR_TYPE_LINK ,MCE_LINK_ERROR_STORE_TIMEOUT , +MCE_INITIATOR_CPU ,MCE_SEV_FATAL , },/* ASYNC is fatal */ +{0x00000000081c0000 ,0x00000000081c0000 , true, +MCE_ERROR_TYPE_RA ,MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0 ,0 ,0 ,0 ,0 ,0 } }; + +struct mce_derror_table { +unsigned long dsisr_value; +bool dar_valid;/* dar is a valid indicator of faulting address */ +unsigned int error_type; +unsigned int error_subtype; +unsigned int initiator; +unsigned int severity; +}; + +static const struct mce_derror_table mce_p7_derror_table[] = { +{0x00008000 , false, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_LOAD_STORE , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00004000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000800 , true, +MCE_ERROR_TYPE_ERAT ,MCE_ERAT_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000400 , true, +MCE_ERROR_TYPE_TLB ,MCE_TLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000100 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_PARITY , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000080 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000040 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_INDETERMINATE ,/* BOTH */ +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0 , false,0 ,0 ,0 ,0 } }; + +static const struct mce_derror_table mce_p8_derror_table[] = { +{0x00008000 , false, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_LOAD_STORE , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00004000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000800 , true, +MCE_ERROR_TYPE_ERAT ,MCE_ERAT_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000400 , true, +MCE_ERROR_TYPE_TLB ,MCE_TLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000200 , true, +MCE_ERROR_TYPE_ERAT ,MCE_ERAT_ERROR_MULTIHIT ,/* SECONDARY ERAT */ +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000100 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_PARITY , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000080 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0 , false,0 ,0 ,0 ,0 } }; + +static const struct mce_derror_table mce_p9_derror_table[] = { +{0x00008000 , false, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_LOAD_STORE , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00004000 , true, +MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00002000 , true, +MCE_ERROR_TYPE_LINK ,MCE_LINK_ERROR_LOAD_TIMEOUT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00001000 , true, +MCE_ERROR_TYPE_LINK ,MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000800 , true, +MCE_ERROR_TYPE_ERAT ,MCE_ERAT_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000400 , true, +MCE_ERROR_TYPE_TLB ,MCE_TLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000200 , false, +MCE_ERROR_TYPE_USER ,MCE_USER_ERROR_TLBIE , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000100 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_PARITY , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000080 , true, +MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_MULTIHIT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000040 , true, +MCE_ERROR_TYPE_RA ,MCE_RA_ERROR_LOAD , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000020 , false, +MCE_ERROR_TYPE_RA ,MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000010 , false, +MCE_ERROR_TYPE_RA ,MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000008 , false, +MCE_ERROR_TYPE_RA ,MCE_RA_ERROR_LOAD_STORE_FOREIGN , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0 , false,0 ,0 ,0 ,0 } }; + +static void mce_get_ierror (struct pt_regs *regs, +const struct mce_ierror_table table[], +struct mce_error_info *mce_err,uint64_t *addr) { -switch (P7_SRR1_MC_IFETCH (srr1)) { -case P7_SRR1_MC_IFETCH_SLB_PARITY : -case P7_SRR1_MC_IFETCH_SLB_MULTIHIT : -case P7_SRR1_MC_IFETCH_SLB_BOTH : -return mce_flush (MCE_FLUSH_SLB ); - -case P7_SRR1_MC_IFETCH_TLB_MULTIHIT : -return mce_flush (MCE_FLUSH_TLB ); -default : -return 0 ; +uint64_t srr1 = regs->msr; +int i; + + *addr =0 ; + +for (i =0 ; table[i].srr1_mask; i++) { +if ((srr1 & table[i].srr1_mask) != table[i].srr1_value) +continue ; + + mce_err->error_type = table[i].error_type; +switch (table[i].error_type) { +case MCE_ERROR_TYPE_UE : + mce_err->u.ue_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_SLB : + mce_err->u.slb_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_ERAT : + mce_err->u.erat_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_TLB : + mce_err->u.tlb_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_USER : + mce_err->u.user_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_RA : + mce_err->u.ra_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_LINK : + mce_err->u.link_error_type = table[i].error_subtype; +break ; + } + mce_err->severity = table[i].severity; + mce_err->initiator = table[i].initiator; +if (table[i].nip_valid) + *addr = regs->nip; +return ; } -} -static void mce_get_common_ierror (struct mce_error_info *mce_err,uint64_t srr1) -{ -switch (P7_SRR1_MC_IFETCH (srr1)) { -case P7_SRR1_MC_IFETCH_SLB_PARITY : - mce_err->error_type =MCE_ERROR_TYPE_SLB ; - mce_err->u.slb_error_type =MCE_SLB_ERROR_PARITY ; -break ; -case P7_SRR1_MC_IFETCH_SLB_MULTIHIT : - mce_err->error_type =MCE_ERROR_TYPE_SLB ; - mce_err->u.slb_error_type =MCE_SLB_ERROR_MULTIHIT ; -break ; -case P7_SRR1_MC_IFETCH_TLB_MULTIHIT : - mce_err->error_type =MCE_ERROR_TYPE_TLB ; - mce_err->u.tlb_error_type =MCE_TLB_ERROR_MULTIHIT ; -break ; -case P7_SRR1_MC_IFETCH_UE : -case P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL : - mce_err->error_type =MCE_ERROR_TYPE_UE ; - mce_err->u.ue_error_type =MCE_UE_ERROR_IFETCH ; -break ; -case P7_SRR1_MC_IFETCH_UE_TLB_RELOAD : - mce_err->error_type =MCE_ERROR_TYPE_UE ; - mce_err->u.ue_error_type = -MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH ; -break ; - } + mce_err->error_type =MCE_ERROR_TYPE_UNKNOWN ; + mce_err->severity =MCE_SEV_ERROR_SYNC ; + mce_err->initiator =MCE_INITIATOR_CPU ; } -static void mce_get_ierror_p7 (struct mce_error_info *mce_err,uint64_t srr1) +static void mce_get_derror (struct pt_regs *regs, +const struct mce_derror_table table[], +struct mce_error_info *mce_err,uint64_t *addr) { -mce_get_common_ierror (mce_err, srr1); -if (P7_SRR1_MC_IFETCH (srr1) ==P7_SRR1_MC_IFETCH_SLB_BOTH ) { - mce_err->error_type =MCE_ERROR_TYPE_SLB ; - mce_err->u.slb_error_type =MCE_SLB_ERROR_INDETERMINATE ; - } -} +uint64_t dsisr = regs->dsisr; +int i; + + *addr =0 ; + +for (i =0 ; table[i].dsisr_value; i++) { +if (!(dsisr & table[i].dsisr_value)) +continue ; + + mce_err->error_type = table[i].error_type; +switch (table[i].error_type) { +case MCE_ERROR_TYPE_UE : + mce_err->u.ue_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_SLB : + mce_err->u.slb_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_ERAT : + mce_err->u.erat_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_TLB : + mce_err->u.tlb_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_USER : + mce_err->u.user_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_RA : + mce_err->u.ra_error_type = table[i].error_subtype; +break ; +case MCE_ERROR_TYPE_LINK : + mce_err->u.link_error_type = table[i].error_subtype; +break ; + } + mce_err->severity = table[i].severity; + mce_err->initiator = table[i].initiator; +if (table[i].dar_valid) + *addr = regs->dar; +else + *addr = regs->nip; -static void mce_get_derror_p7 (struct mce_error_info *mce_err,uint64_t dsisr) -{ -if (dsisr &P7_DSISR_MC_UE ) { - mce_err->error_type =MCE_ERROR_TYPE_UE ; - mce_err->u.ue_error_type =MCE_UE_ERROR_LOAD_STORE ; - }else if (dsisr &P7_DSISR_MC_UE_TABLEWALK ) { - mce_err->error_type =MCE_ERROR_TYPE_UE ; - mce_err->u.ue_error_type = -MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE ; - }else if (dsisr &P7_DSISR_MC_ERAT_MULTIHIT ) { - mce_err->error_type =MCE_ERROR_TYPE_ERAT ; - mce_err->u.erat_error_type =MCE_ERAT_ERROR_MULTIHIT ; - }else if (dsisr &P7_DSISR_MC_SLB_MULTIHIT ) { - mce_err->error_type =MCE_ERROR_TYPE_SLB ; - mce_err->u.slb_error_type =MCE_SLB_ERROR_MULTIHIT ; - }else if (dsisr &P7_DSISR_MC_SLB_PARITY_MFSLB ) { - mce_err->error_type =MCE_ERROR_TYPE_SLB ; - mce_err->u.slb_error_type =MCE_SLB_ERROR_PARITY ; - }else if (dsisr &P7_DSISR_MC_TLB_MULTIHIT_MFTLB ) { - mce_err->error_type =MCE_ERROR_TYPE_TLB ; - mce_err->u.tlb_error_type =MCE_TLB_ERROR_MULTIHIT ; - }else if (dsisr &P7_DSISR_MC_SLB_MULTIHIT_PARITY ) { - mce_err->error_type =MCE_ERROR_TYPE_SLB ; - mce_err->u.slb_error_type =MCE_SLB_ERROR_INDETERMINATE ; +return ; } + + mce_err->error_type =MCE_ERROR_TYPE_UNKNOWN ; + mce_err->severity =MCE_SEV_ERROR_SYNC ; + mce_err->initiator =MCE_INITIATOR_CPU ; }static long mce_handle_ue_error (struct pt_regs *regs)
@@ -358,18 +571,41 @@ static long mce_handle_ue_error(struct pt_regs *regs)return handled; } +static long mce_handle_derror_p7 (uint64_t dsisr) +{ +return mce_handle_flush_derrors (dsisr, +P7_DSISR_MC_SLB_ERRORS , +P7_DSISR_MC_TLB_MULTIHIT_MFTLB , +0 ); +} + +static long mce_handle_ierror_p7 (uint64_t srr1) +{ +switch (P7_SRR1_MC_IFETCH (srr1)) { +case P7_SRR1_MC_IFETCH_SLB_PARITY : +case P7_SRR1_MC_IFETCH_SLB_MULTIHIT : +case P7_SRR1_MC_IFETCH_SLB_BOTH : +return mce_flush (MCE_FLUSH_SLB ); + +case P7_SRR1_MC_IFETCH_TLB_MULTIHIT : +return mce_flush (MCE_FLUSH_TLB ); +default : +return 0 ; + } +} +long __machine_check_early_realmode_p7 (struct pt_regs *regs) {uint64_t srr1, nip, addr;long handled =1 ;struct mce_error_info mce_error_info = {0 }; - mce_error_info.severity =MCE_SEV_ERROR_SYNC ; - mce_error_info.initiator =MCE_INITIATOR_CPU ; - srr1 = regs->msr; nip = regs->nip; +/* P7 DD1 leaves top bits of DSISR undefined */ + regs->dsisr &=0x0000ffff ; +/* * Handle memory errors depending whether this was a load/store or * ifetch exception. Also, populate the mce error_type and
@@ -378,12 +614,12 @@ long __machine_check_early_realmode_p7(struct pt_regs *regs)*/ if (P7_SRR1_MC_LOADSTORE (srr1)) { handled =mce_handle_derror_p7 (regs->dsisr); -mce_get_derror_p7 (&mce_error_info, regs->dsisr); - addr = regs->dar; +mce_get_derror (regs, mce_p7_derror_table, + &mce_error_info, &addr); }else { handled =mce_handle_ierror_p7 (srr1); -mce_get_ierror_p7 (&mce_error_info, srr1); - addr = regs->nip; +mce_get_ierror (regs, mce_p7_ierror_table, + &mce_error_info, &addr); }/* Handle UE error. */
@@ -394,24 +630,6 @@ long __machine_check_early_realmode_p7(struct pt_regs *regs)return handled; } -static void mce_get_ierror_p8 (struct mce_error_info *mce_err,uint64_t srr1) -{ -mce_get_common_ierror (mce_err, srr1); -if (P7_SRR1_MC_IFETCH (srr1) ==P8_SRR1_MC_IFETCH_ERAT_MULTIHIT ) { - mce_err->error_type =MCE_ERROR_TYPE_ERAT ; - mce_err->u.erat_error_type =MCE_ERAT_ERROR_MULTIHIT ; - } -} - -static void mce_get_derror_p8 (struct mce_error_info *mce_err,uint64_t dsisr) -{ -mce_get_derror_p7 (mce_err, dsisr); -if (dsisr &P8_DSISR_MC_ERAT_MULTIHIT_SEC ) { - mce_err->error_type =MCE_ERROR_TYPE_ERAT ; - mce_err->u.erat_error_type =MCE_ERAT_ERROR_MULTIHIT ; - } -} -static long mce_handle_ierror_p8 (uint64_t srr1) {switch (P7_SRR1_MC_IFETCH (srr1)) {
@@ -441,20 +659,17 @@ long __machine_check_early_realmode_p8(struct pt_regs *regs)long handled =1 ;struct mce_error_info mce_error_info = {0 }; - mce_error_info.severity =MCE_SEV_ERROR_SYNC ; - mce_error_info.initiator =MCE_INITIATOR_CPU ; - srr1 = regs->msr; nip = regs->nip;if (P7_SRR1_MC_LOADSTORE (srr1)) { handled =mce_handle_derror_p8 (regs->dsisr); -mce_get_derror_p8 (&mce_error_info, regs->dsisr); - addr = regs->dar; +mce_get_derror (regs, mce_p8_derror_table, + &mce_error_info, &addr); }else { handled =mce_handle_ierror_p8 (srr1); -mce_get_ierror_p8 (&mce_error_info, srr1); - addr = regs->nip; +mce_get_ierror (regs, mce_p8_ierror_table, + &mce_error_info, &addr); }/* Handle UE error. */
@@ -495,138 +710,6 @@ static int mce_handle_ierror_p9(struct pt_regs *regs) } } -static void mce_get_derror_p9 (struct pt_regs *regs, -struct mce_error_info *mce_err,uint64_t *addr) -{ -uint64_t dsisr = regs->dsisr; - - mce_err->severity =MCE_SEV_ERROR_SYNC ; - mce_err->initiator =MCE_INITIATOR_CPU ; - -if (dsisr &P9_DSISR_MC_USER_TLBIE ) - *addr = regs->nip; -else - *addr = regs->dar; - -if (dsisr &P9_DSISR_MC_UE ) { - mce_err->error_type =MCE_ERROR_TYPE_UE ; - mce_err->u.ue_error_type =MCE_UE_ERROR_LOAD_STORE ; - }else if (dsisr &P9_DSISR_MC_UE_TABLEWALK ) { - mce_err->error_type =MCE_ERROR_TYPE_UE ; - mce_err->u.ue_error_type =MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE ; - }else if (dsisr &P9_DSISR_MC_LINK_LOAD_TIMEOUT ) { - mce_err->error_type =MCE_ERROR_TYPE_LINK ; - mce_err->u.link_error_type =MCE_LINK_ERROR_LOAD_TIMEOUT ; - }else if (dsisr &P9_DSISR_MC_LINK_TABLEWALK_TIMEOUT ) { - mce_err->error_type =MCE_ERROR_TYPE_LINK ; - mce_err->u.link_error_type =MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT ; - }else if (dsisr &P9_DSISR_MC_ERAT_MULTIHIT ) { - mce_err->error_type =MCE_ERROR_TYPE_ERAT ; - mce_err->u.erat_error_type =MCE_ERAT_ERROR_MULTIHIT ; - }else if (dsisr &P9_DSISR_MC_TLB_MULTIHIT_MFTLB ) { - mce_err->error_type =MCE_ERROR_TYPE_TLB ; - mce_err->u.tlb_error_type =MCE_TLB_ERROR_MULTIHIT ; - }else if (dsisr &P9_DSISR_MC_USER_TLBIE ) { - mce_err->error_type =MCE_ERROR_TYPE_USER ; - mce_err->u.user_error_type =MCE_USER_ERROR_TLBIE ; - }else if (dsisr &P9_DSISR_MC_SLB_PARITY_MFSLB ) { - mce_err->error_type =MCE_ERROR_TYPE_SLB ; - mce_err->u.slb_error_type =MCE_SLB_ERROR_PARITY ; - }else if (dsisr &P9_DSISR_MC_SLB_MULTIHIT_MFSLB ) { - mce_err->error_type =MCE_ERROR_TYPE_SLB ; - mce_err->u.slb_error_type =MCE_SLB_ERROR_MULTIHIT ; - }else if (dsisr &P9_DSISR_MC_RA_LOAD ) { - mce_err->error_type =MCE_ERROR_TYPE_RA ; - mce_err->u.ra_error_type =MCE_RA_ERROR_LOAD ; - }else if (dsisr &P9_DSISR_MC_RA_TABLEWALK ) { - mce_err->error_type =MCE_ERROR_TYPE_RA ; - mce_err->u.ra_error_type =MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE ; - }else if (dsisr &P9_DSISR_MC_RA_TABLEWALK_FOREIGN ) { - mce_err->error_type =MCE_ERROR_TYPE_RA ; - mce_err->u.ra_error_type =MCE_RA_ERROR_PAGE_TABLE_WALK_LOAD_STORE_FOREIGN ; - }else if (dsisr &P9_DSISR_MC_RA_FOREIGN ) { - mce_err->error_type =MCE_ERROR_TYPE_RA ; - mce_err->u.ra_error_type =MCE_RA_ERROR_LOAD_STORE_FOREIGN ; - } -} - -static void mce_get_ierror_p9 (struct pt_regs *regs, -struct mce_error_info *mce_err,uint64_t *addr) -{ -uint64_t srr1 = regs->msr; - -switch (P9_SRR1_MC_IFETCH (srr1)) { -case P9_SRR1_MC_IFETCH_RA_ASYNC_STORE : -case P9_SRR1_MC_IFETCH_LINK_ASYNC_STORE_TIMEOUT : - mce_err->severity =MCE_SEV_FATAL ; -break ; -default : - mce_err->severity =MCE_SEV_ERROR_SYNC ; -break ; - } - - mce_err->initiator =MCE_INITIATOR_CPU ; - - *addr = regs->nip; - -switch (P9_SRR1_MC_IFETCH (srr1)) { -case P9_SRR1_MC_IFETCH_UE : - mce_err->error_type =MCE_ERROR_TYPE_UE ; - mce_err->u.ue_error_type =MCE_UE_ERROR_IFETCH ; -break ; -case P9_SRR1_MC_IFETCH_SLB_PARITY : - mce_err->error_type =MCE_ERROR_TYPE_SLB ; - mce_err->u.slb_error_type =MCE_SLB_ERROR_PARITY ; -break ; -case P9_SRR1_MC_IFETCH_SLB_MULTIHIT : - mce_err->error_type =MCE_ERROR_TYPE_SLB ; - mce_err->u.slb_error_type =MCE_SLB_ERROR_MULTIHIT ; -break ; -case P9_SRR1_MC_IFETCH_ERAT_MULTIHIT : - mce_err->error_type =MCE_ERROR_TYPE_ERAT ; - mce_err->u.erat_error_type =MCE_ERAT_ERROR_MULTIHIT ; -break ; -case P9_SRR1_MC_IFETCH_TLB_MULTIHIT : - mce_err->error_type =MCE_ERROR_TYPE_TLB ; - mce_err->u.tlb_error_type =MCE_TLB_ERROR_MULTIHIT ; -break ; -case P9_SRR1_MC_IFETCH_UE_TLB_RELOAD : - mce_err->error_type =MCE_ERROR_TYPE_UE ; - mce_err->u.ue_error_type =MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH ; -break ; -case P9_SRR1_MC_IFETCH_LINK_TIMEOUT : - mce_err->error_type =MCE_ERROR_TYPE_LINK ; - mce_err->u.link_error_type =MCE_LINK_ERROR_IFETCH_TIMEOUT ; -break ; -case P9_SRR1_MC_IFETCH_LINK_TABLEWALK_TIMEOUT : - mce_err->error_type =MCE_ERROR_TYPE_LINK ; - mce_err->u.link_error_type =MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT ; -break ; -case P9_SRR1_MC_IFETCH_RA : - mce_err->error_type =MCE_ERROR_TYPE_RA ; - mce_err->u.ra_error_type =MCE_RA_ERROR_IFETCH ; -break ; -case P9_SRR1_MC_IFETCH_RA_TABLEWALK : - mce_err->error_type =MCE_ERROR_TYPE_RA ; - mce_err->u.ra_error_type =MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH ; -break ; -case P9_SRR1_MC_IFETCH_RA_ASYNC_STORE : - mce_err->error_type =MCE_ERROR_TYPE_RA ; - mce_err->u.ra_error_type =MCE_RA_ERROR_STORE ; -break ; -case P9_SRR1_MC_IFETCH_LINK_ASYNC_STORE_TIMEOUT : - mce_err->error_type =MCE_ERROR_TYPE_LINK ; - mce_err->u.link_error_type =MCE_LINK_ERROR_STORE_TIMEOUT ; -break ; -case P9_SRR1_MC_IFETCH_RA_TABLEWALK_FOREIGN : - mce_err->error_type =MCE_ERROR_TYPE_RA ; - mce_err->u.ra_error_type =MCE_RA_ERROR_PAGE_TABLE_WALK_IFETCH_FOREIGN ; -break ; -default : -break ; - } -} -long __machine_check_early_realmode_p9 (struct pt_regs *regs) {uint64_t nip, addr;
@@ -637,10 +720,12 @@ long __machine_check_early_realmode_p9(struct pt_regs *regs)if (P9_SRR1_MC_LOADSTORE (regs->msr)) { handled =mce_handle_derror_p9 (regs); -mce_get_derror_p9 (regs, &mce_error_info, &addr); +mce_get_derror (regs, mce_p9_derror_table, + &mce_error_info, &addr); }else { handled =mce_handle_ierror_p9 (regs); -mce_get_ierror_p9 (regs, &mce_error_info, &addr); +mce_get_ierror (regs, mce_p9_ierror_table, + &mce_error_info, &addr); }/* Handle UE error. */
Signature · 1 line
2.11.0
Nicholas Piggin
reviewerPATCH 5/6 powerpc/64s: data driven machine check handling
In reply to Nicholas PigginMove the handling (corrective action) of machine checks to the table based evaluation.
This changes P7 and P8 ERAT flushing from using SLB flush to using ERAT flush.
--- arch/powerpc/kernel/mce_power.c | 328 +++++++++------------------------------- 1 file changed, 74 insertions(+), 254 deletions(-)
arch/powerpc/kernel/mce_power.c +74 -254
@@ -147,111 +147,7 @@ static int mce_flush(int what)return 0 ; } -static int mce_handle_flush_derrors (uint64_t dsisr,uint64_t slb,uint64_t tlb,uint64_t erat) -{ -if ((dsisr & slb) &&mce_flush (MCE_FLUSH_SLB )) - dsisr &= ~slb; -if ((dsisr & erat) &&mce_flush (MCE_FLUSH_ERAT )) - dsisr &= ~erat; -if ((dsisr & tlb) &&mce_flush (MCE_FLUSH_TLB )) - dsisr &= ~tlb; -/* Any other errors we don't understand? */ -if (dsisr) -return 0 ; -return 1 ; -} - - -/* -* Machine Check bits on power7 and power8 -*/ -#define P7_SRR1_MC_LOADSTORE (srr1) ((srr1) & PPC_BIT(42))/* P8 too */ - -/* SRR1 bits for machine check (On Power7 and Power8) */ -#define P7_SRR1_MC_IFETCH (srr1) ((srr1) & PPC_BITMASK(43, 45))/* P8 too */ - -#define P7_SRR1_MC_IFETCH_UE (0x1 << PPC_BITLSHIFT(45))/* P8 too */ -#define P7_SRR1_MC_IFETCH_SLB_PARITY (0x2 << PPC_BITLSHIFT(45))/* P8 too */ -#define P7_SRR1_MC_IFETCH_SLB_MULTIHIT (0x3 << PPC_BITLSHIFT(45))/* P8 too */ -#define P7_SRR1_MC_IFETCH_SLB_BOTH (0x4 << PPC_BITLSHIFT(45)) -#define P7_SRR1_MC_IFETCH_TLB_MULTIHIT (0x5 << PPC_BITLSHIFT(45))/* P8 too */ -#define P7_SRR1_MC_IFETCH_UE_TLB_RELOAD (0x6 << PPC_BITLSHIFT(45))/* P8 too */ -#define P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL (0x7 << PPC_BITLSHIFT(45)) - -/* SRR1 bits for machine check (On Power8) */ -#define P8_SRR1_MC_IFETCH_ERAT_MULTIHIT (0x4 << PPC_BITLSHIFT(45)) - -/* DSISR bits for machine check (On Power7 and Power8) */ -#define P7_DSISR_MC_UE (PPC_BIT(48))/* P8 too */ -#define P7_DSISR_MC_UE_TABLEWALK (PPC_BIT(49))/* P8 too */ -#define P7_DSISR_MC_ERAT_MULTIHIT (PPC_BIT(52))/* P8 too */ -#define P7_DSISR_MC_TLB_MULTIHIT_MFTLB (PPC_BIT(53))/* P8 too */ -#define P7_DSISR_MC_SLB_PARITY_MFSLB (PPC_BIT(55))/* P8 too */ -#define P7_DSISR_MC_SLB_MULTIHIT (PPC_BIT(56))/* P8 too */ -#define P7_DSISR_MC_SLB_MULTIHIT_PARITY (PPC_BIT(57))/* P8 too */ - -/* -* DSISR bits for machine check (Power8) in addition to above. -* Secondary DERAT Multihit -*/ -#define P8_DSISR_MC_ERAT_MULTIHIT_SEC (PPC_BIT(54)) - -/* SLB error bits */ -#define P7_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_ERAT_MULTIHIT | \ - P7_DSISR_MC_SLB_PARITY_MFSLB | \ - P7_DSISR_MC_SLB_MULTIHIT | \ - P7_DSISR_MC_SLB_MULTIHIT_PARITY) - -#define P8_DSISR_MC_SLB_ERRORS (P7_DSISR_MC_SLB_ERRORS | \ - P8_DSISR_MC_ERAT_MULTIHIT_SEC) - -/* -* Machine Check bits on power9 -*/ -#define P9_SRR1_MC_LOADSTORE (srr1) (((srr1) >> PPC_BITLSHIFT(42)) & 1) - -#define P9_SRR1_MC_IFETCH (srr1) ( \ - PPC_BITEXTRACT(srr1, 45, 0) | \ - PPC_BITEXTRACT(srr1, 44, 1) | \ - PPC_BITEXTRACT(srr1, 43, 2) | \ - PPC_BITEXTRACT(srr1, 36, 3) ) - -/* 0 is reserved */ -#define P9_SRR1_MC_IFETCH_UE 1 -#define P9_SRR1_MC_IFETCH_SLB_PARITY 2 -#define P9_SRR1_MC_IFETCH_SLB_MULTIHIT 3 -#define P9_SRR1_MC_IFETCH_ERAT_MULTIHIT 4 -#define P9_SRR1_MC_IFETCH_TLB_MULTIHIT 5 -#define P9_SRR1_MC_IFETCH_UE_TLB_RELOAD 6 -/* 7 is reserved */ -#define P9_SRR1_MC_IFETCH_LINK_TIMEOUT 8 -#define P9_SRR1_MC_IFETCH_LINK_TABLEWALK_TIMEOUT 9 -/* 10 ? */ -#define P9_SRR1_MC_IFETCH_RA 11 -#define P9_SRR1_MC_IFETCH_RA_TABLEWALK 12 -#define P9_SRR1_MC_IFETCH_RA_ASYNC_STORE 13 -#define P9_SRR1_MC_IFETCH_LINK_ASYNC_STORE_TIMEOUT 14 -#define P9_SRR1_MC_IFETCH_RA_TABLEWALK_FOREIGN 15 - -/* DSISR bits for machine check (On Power9) */ -#define P9_DSISR_MC_UE (PPC_BIT(48)) -#define P9_DSISR_MC_UE_TABLEWALK (PPC_BIT(49)) -#define P9_DSISR_MC_LINK_LOAD_TIMEOUT (PPC_BIT(50)) -#define P9_DSISR_MC_LINK_TABLEWALK_TIMEOUT (PPC_BIT(51)) -#define P9_DSISR_MC_ERAT_MULTIHIT (PPC_BIT(52)) -#define P9_DSISR_MC_TLB_MULTIHIT_MFTLB (PPC_BIT(53)) -#define P9_DSISR_MC_USER_TLBIE (PPC_BIT(54)) -#define P9_DSISR_MC_SLB_PARITY_MFSLB (PPC_BIT(55)) -#define P9_DSISR_MC_SLB_MULTIHIT_MFSLB (PPC_BIT(56)) -#define P9_DSISR_MC_RA_LOAD (PPC_BIT(57)) -#define P9_DSISR_MC_RA_TABLEWALK (PPC_BIT(58)) -#define P9_DSISR_MC_RA_TABLEWALK_FOREIGN (PPC_BIT(59)) -#define P9_DSISR_MC_RA_FOREIGN (PPC_BIT(60)) - -/* SLB error bits */ -#define P9_DSISR_MC_SLB_ERRORS (P9_DSISR_MC_ERAT_MULTIHIT | \ - P9_DSISR_MC_SLB_PARITY_MFSLB | \ - P9_DSISR_MC_SLB_MULTIHIT_MFSLB) +#define SRR1_MC_LOADSTORE (srr1) ((srr1) & PPC_BIT(42))struct mce_ierror_table {unsigned long srr1_mask;
@@ -452,11 +348,12 @@ static const struct mce_derror_table mce_p9_derror_table[] = { MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, }, { 0, false, 0, 0, 0, 0 } }; -static void mce_get_ierror (struct pt_regs *regs, +static int mce_handle_ierror (struct pt_regs *regs,const struct mce_ierror_table table[],struct mce_error_info *mce_err,uint64_t *addr) {uint64_t srr1 = regs->msr; +int handled =0 ;int i; *addr =0 ;
@@ -465,6 +362,20 @@ static void mce_get_ierror(struct pt_regs *regs,if ((srr1 & table[i].srr1_mask) != table[i].srr1_value)continue ; +/* attempt to correct the error */ +switch (table[i].error_type) { +case MCE_ERROR_TYPE_SLB : + handled =mce_flush (MCE_FLUSH_SLB ); +break ; +case MCE_ERROR_TYPE_ERAT : + handled =mce_flush (MCE_FLUSH_ERAT ); +break ; +case MCE_ERROR_TYPE_TLB : + handled =mce_flush (MCE_FLUSH_TLB ); +break ; + } + +/* now fill in mce_error_info */ mce_err->error_type = table[i].error_type;switch (table[i].error_type) {case MCE_ERROR_TYPE_UE :
@@ -493,19 +404,23 @@ static void mce_get_ierror(struct pt_regs *regs, mce_err->initiator = table[i].initiator;if (table[i].nip_valid) *addr = regs->nip; -return ; +return handled; } mce_err->error_type =MCE_ERROR_TYPE_UNKNOWN ; mce_err->severity =MCE_SEV_ERROR_SYNC ; mce_err->initiator =MCE_INITIATOR_CPU ; + +return 0 ; } -static void mce_get_derror (struct pt_regs *regs, +static int mce_handle_derror (struct pt_regs *regs,const struct mce_derror_table table[],struct mce_error_info *mce_err,uint64_t *addr) {uint64_t dsisr = regs->dsisr; +int handled =0 ; +int found =0 ;int i; *addr =0 ;
@@ -514,6 +429,31 @@ static void mce_get_derror(struct pt_regs *regs,if (!(dsisr & table[i].dsisr_value))continue ; +/* attempt to correct the error */ +switch (table[i].error_type) { +case MCE_ERROR_TYPE_SLB : +if (mce_flush (MCE_FLUSH_SLB )) + handled =1 ; +break ; +case MCE_ERROR_TYPE_ERAT : +if (mce_flush (MCE_FLUSH_ERAT )) + handled =1 ; +break ; +case MCE_ERROR_TYPE_TLB : +if (mce_flush (MCE_FLUSH_TLB )) + handled =1 ; +break ; + } + +/* +* Attempt to handle multiple conditions, but only return +* one. Ensure uncorrectable errors are first in the table +* to match. +*/ +if (found) +continue ; + +/* now fill in mce_error_info */ mce_err->error_type = table[i].error_type;switch (table[i].error_type) {case MCE_ERROR_TYPE_UE :
@@ -545,12 +485,17 @@ static void mce_get_derror(struct pt_regs *regs,else *addr = regs->nip; -return ; + found =1 ; } +if (found) +return handled; + mce_err->error_type =MCE_ERROR_TYPE_UNKNOWN ; mce_err->severity =MCE_SEV_ERROR_SYNC ; mce_err->initiator =MCE_INITIATOR_CPU ; + +return 0 ; }static long mce_handle_ue_error (struct pt_regs *regs)
@@ -571,167 +516,42 @@ static long mce_handle_ue_error(struct pt_regs *regs)return handled; } -static long mce_handle_derror_p7 (uint64_t dsisr) -{ -return mce_handle_flush_derrors (dsisr, -P7_DSISR_MC_SLB_ERRORS , -P7_DSISR_MC_TLB_MULTIHIT_MFTLB , -0 ); -} - -static long mce_handle_ierror_p7 (uint64_t srr1) -{ -switch (P7_SRR1_MC_IFETCH (srr1)) { -case P7_SRR1_MC_IFETCH_SLB_PARITY : -case P7_SRR1_MC_IFETCH_SLB_MULTIHIT : -case P7_SRR1_MC_IFETCH_SLB_BOTH : -return mce_flush (MCE_FLUSH_SLB ); - -case P7_SRR1_MC_IFETCH_TLB_MULTIHIT : -return mce_flush (MCE_FLUSH_TLB ); -default : -return 0 ; - } -} - -long __machine_check_early_realmode_p7 (struct pt_regs *regs) +static long mce_handle_error (struct pt_regs *regs, +const struct mce_derror_table dtable[], +const struct mce_ierror_table itable[]) { -uint64_t srr1, nip, addr; -long handled =1 ; -struct mce_error_info mce_error_info = {0 }; - - srr1 = regs->msr; - nip = regs->nip; +struct mce_error_info mce_err = {0 }; +uint64_t addr; +uint64_t srr1 = regs->msr; +long handled; -/* P7 DD1 leaves top bits of DSISR undefined */ - regs->dsisr &=0x0000ffff ; +if (SRR1_MC_LOADSTORE (srr1)) + handled =mce_handle_derror (regs, dtable, &mce_err, &addr); +else + handled =mce_handle_ierror (regs, itable, &mce_err, &addr); -/* -* Handle memory errors depending whether this was a load/store or -* ifetch exception. Also, populate the mce error_type and -* type-specific error_type from either SRR1 or DSISR, depending -* whether this was a load/store or ifetch exception -*/ -if (P7_SRR1_MC_LOADSTORE (srr1)) { - handled =mce_handle_derror_p7 (regs->dsisr); -mce_get_derror (regs, mce_p7_derror_table, - &mce_error_info, &addr); - }else { - handled =mce_handle_ierror_p7 (srr1); -mce_get_ierror (regs, mce_p7_ierror_table, - &mce_error_info, &addr); - } - -/* Handle UE error. */ -if (mce_error_info.error_type ==MCE_ERROR_TYPE_UE ) +if (!handled && mce_err.error_type ==MCE_ERROR_TYPE_UE ) handled =mce_handle_ue_error (regs); -save_mce_event (regs, handled, &mce_error_info, nip, addr); -return handled; -} - -static long mce_handle_ierror_p8 (uint64_t srr1) -{ -switch (P7_SRR1_MC_IFETCH (srr1)) { -case P7_SRR1_MC_IFETCH_SLB_PARITY : -case P7_SRR1_MC_IFETCH_SLB_MULTIHIT : -case P8_SRR1_MC_IFETCH_ERAT_MULTIHIT : -return mce_flush (MCE_FLUSH_SLB ); - -case P7_SRR1_MC_IFETCH_TLB_MULTIHIT : -return mce_flush (MCE_FLUSH_TLB ); -default : -return 0 ; - } -} - -static long mce_handle_derror_p8 (uint64_t dsisr) -{ -return mce_handle_flush_derrors (dsisr, -P8_DSISR_MC_SLB_ERRORS , -P7_DSISR_MC_TLB_MULTIHIT_MFTLB , -0 ); -} - -long __machine_check_early_realmode_p8 (struct pt_regs *regs) -{ -uint64_t srr1, nip, addr; -long handled =1 ; -struct mce_error_info mce_error_info = {0 }; - - srr1 = regs->msr; - nip = regs->nip; - -if (P7_SRR1_MC_LOADSTORE (srr1)) { - handled =mce_handle_derror_p8 (regs->dsisr); -mce_get_derror (regs, mce_p8_derror_table, - &mce_error_info, &addr); - }else { - handled =mce_handle_ierror_p8 (srr1); -mce_get_ierror (regs, mce_p8_ierror_table, - &mce_error_info, &addr); - } - -/* Handle UE error. */ -if (mce_error_info.error_type ==MCE_ERROR_TYPE_UE ) - handled =mce_handle_ue_error (regs); +save_mce_event (regs, handled, &mce_err, regs->nip, addr); -save_mce_event (regs, handled, &mce_error_info, nip, addr);return handled; } -static int mce_handle_derror_p9 (struct pt_regs *regs) +long __machine_check_early_realmode_p7 (struct pt_regs *regs) { -uint64_t dsisr = regs->dsisr; - -return mce_handle_flush_derrors (dsisr, -P9_DSISR_MC_SLB_PARITY_MFSLB | -P9_DSISR_MC_SLB_MULTIHIT_MFSLB , - -P9_DSISR_MC_TLB_MULTIHIT_MFTLB , +/* P7 DD1 leaves top bits of DSISR undefined */ + regs->dsisr &=0x0000ffff ; -P9_DSISR_MC_ERAT_MULTIHIT ); +return mce_handle_error (regs, mce_p7_derror_table, mce_p7_ierror_table); } -static int mce_handle_ierror_p9 (struct pt_regs *regs) +long __machine_check_early_realmode_p8 (struct pt_regs *regs) { -uint64_t srr1 = regs->msr; - -switch (P9_SRR1_MC_IFETCH (srr1)) { -case P9_SRR1_MC_IFETCH_SLB_PARITY : -case P9_SRR1_MC_IFETCH_SLB_MULTIHIT : -return mce_flush (MCE_FLUSH_SLB ); -case P9_SRR1_MC_IFETCH_TLB_MULTIHIT : -return mce_flush (MCE_FLUSH_TLB ); -case P9_SRR1_MC_IFETCH_ERAT_MULTIHIT : -return mce_flush (MCE_FLUSH_ERAT ); -default : -return 0 ; - } +return mce_handle_error (regs, mce_p8_derror_table, mce_p8_ierror_table); }long __machine_check_early_realmode_p9 (struct pt_regs *regs) { -uint64_t nip, addr; -long handled; -struct mce_error_info mce_error_info = {0 }; - - nip = regs->nip; - -if (P9_SRR1_MC_LOADSTORE (regs->msr)) { - handled =mce_handle_derror_p9 (regs); -mce_get_derror (regs, mce_p9_derror_table, - &mce_error_info, &addr); - }else { - handled =mce_handle_ierror_p9 (regs); -mce_get_ierror (regs, mce_p9_ierror_table, - &mce_error_info, &addr); - } - -/* Handle UE error. */ -if (mce_error_info.error_type ==MCE_ERROR_TYPE_UE ) - handled =mce_handle_ue_error (regs); - -save_mce_event (regs, handled, &mce_error_info, nip, addr); -return handled; +return mce_handle_error (regs, mce_p9_derror_table, mce_p9_ierror_table); }
Signature · 1 line
2.11.0
Nicholas Piggin
reviewerPATCH 6/6 powerpc/64s: POWER8 add missing machine check definitions
In reply to Nicholas PigginPOWER8 uses bit 36 in SRR1 like POWER9 for i-side machine checks, and contains several conditions for link timeouts that are not currently handled.
--- arch/powerpc/kernel/mce_power.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-)
arch/powerpc/kernel/mce_power.c +19 -7
@@ -184,27 +184,33 @@ static const struct mce_ierror_table mce_p7_ierror_table[] = { { 0, 0, 0, 0, 0, 0 } };static const struct mce_ierror_table mce_p8_ierror_table[] = { -{0x00000000001c0000 ,0x0000000000040000 , true, +{0x00000000081c0000 ,0x0000000000040000 , true,MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_IFETCH ,MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, -{0x00000000001c0000 ,0x0000000000080000 , true, +{0x00000000081c0000 ,0x0000000000080000 , true,MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_PARITY ,MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, -{0x00000000001c0000 ,0x00000000000c0000 , true, +{0x00000000081c0000 ,0x00000000000c0000 , true,MCE_ERROR_TYPE_SLB ,MCE_SLB_ERROR_MULTIHIT ,MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, -{0x00000000001c0000 ,0x0000000000100000 , true, +{0x00000000081c0000 ,0x0000000000100000 , true,MCE_ERROR_TYPE_ERAT ,MCE_ERAT_ERROR_MULTIHIT ,MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, -{0x00000000001c0000 ,0x0000000000140000 , true, +{0x00000000081c0000 ,0x0000000000140000 , true,MCE_ERROR_TYPE_TLB ,MCE_TLB_ERROR_MULTIHIT ,MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, -{0x00000000001c0000 ,0x0000000000180000 , true, +{0x00000000081c0000 ,0x0000000000180000 , true,MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH ,MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, -{0x00000000001c0000 ,0x00000000001c0000 , true, +{0x00000000081c0000 ,0x00000000001c0000 , true,MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_IFETCH ,MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x0000000008000000 , true, +MCE_ERROR_TYPE_LINK ,MCE_LINK_ERROR_IFETCH_TIMEOUT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, +{0x00000000081c0000 ,0x0000000008040000 , true, +MCE_ERROR_TYPE_LINK ,MCE_LINK_ERROR_PAGE_TABLE_WALK_IFETCH_TIMEOUT , +MCE_INITIATOR_CPU ,MCE_SEV_ERROR_SYNC , }, {0 ,0 ,0 ,0 ,0 ,0 } };static const struct mce_ierror_table mce_p9_ierror_table[] = {
@@ -289,6 +295,12 @@ static const struct mce_derror_table mce_p8_derror_table[] = { {0x00004000 , true,MCE_ERROR_TYPE_UE ,MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE , MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, }, +{ 0x00002000, true, +MCE_ERROR_TYPE_LINK ,MCE_LINK_ERROR_LOAD_TIMEOUT , + MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, }, +{ 0x00001000, true, +MCE_ERROR_TYPE_LINK ,MCE_LINK_ERROR_PAGE_TABLE_WALK_LOAD_STORE_TIMEOUT , + MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, }, { 0x00000800, true,MCE_ERROR_TYPE_ERAT ,MCE_ERAT_ERROR_MULTIHIT , MCE_INITIATOR_CPU, MCE_SEV_ERROR_SYNC, },
Signature · 1 line
2.11.0