diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
| -rw-r--r-- | arch/powerpc/kernel/traps.c | 88 | 
1 files changed, 87 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 3031fc712ad..25fc33984c2 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -1,5 +1,6 @@  /*   *  Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org) + *  Copyright 2007-2010 Freescale Semiconductor, Inc.   *   *  This program is free software; you can redistribute it and/or   *  modify it under the terms of the GNU General Public License @@ -305,7 +306,7 @@ static inline int check_io_access(struct pt_regs *regs)  #ifndef CONFIG_FSL_BOOKE  #define get_mc_reason(regs)	((regs)->dsisr)  #else -#define get_mc_reason(regs)	(mfspr(SPRN_MCSR) & MCSR_MASK) +#define get_mc_reason(regs)	(mfspr(SPRN_MCSR))  #endif  #define REASON_FP		ESR_FP  #define REASON_ILLEGAL		(ESR_PIL | ESR_PUO) @@ -421,6 +422,91 @@ int machine_check_47x(struct pt_regs *regs)  	return 0;  }  #elif defined(CONFIG_E500) +int machine_check_e500mc(struct pt_regs *regs) +{ +	unsigned long mcsr = mfspr(SPRN_MCSR); +	unsigned long reason = mcsr; +	int recoverable = 1; + +	printk("Machine check in kernel mode.\n"); +	printk("Caused by (from MCSR=%lx): ", reason); + +	if (reason & MCSR_MCP) +		printk("Machine Check Signal\n"); + +	if (reason & MCSR_ICPERR) { +		printk("Instruction Cache Parity Error\n"); + +		/* +		 * This is recoverable by invalidating the i-cache. +		 */ +		mtspr(SPRN_L1CSR1, mfspr(SPRN_L1CSR1) | L1CSR1_ICFI); +		while (mfspr(SPRN_L1CSR1) & L1CSR1_ICFI) +			; + +		/* +		 * This will generally be accompanied by an instruction +		 * fetch error report -- only treat MCSR_IF as fatal +		 * if it wasn't due to an L1 parity error. +		 */ +		reason &= ~MCSR_IF; +	} + +	if (reason & MCSR_DCPERR_MC) { +		printk("Data Cache Parity Error\n"); +		recoverable = 0; +	} + +	if (reason & MCSR_L2MMU_MHIT) { +		printk("Hit on multiple TLB entries\n"); +		recoverable = 0; +	} + +	if (reason & MCSR_NMI) +		printk("Non-maskable interrupt\n"); + +	if (reason & MCSR_IF) { +		printk("Instruction Fetch Error Report\n"); +		recoverable = 0; +	} + +	if (reason & MCSR_LD) { +		printk("Load Error Report\n"); +		recoverable = 0; +	} + +	if (reason & MCSR_ST) { +		printk("Store Error Report\n"); +		recoverable = 0; +	} + +	if (reason & MCSR_LDG) { +		printk("Guarded Load Error Report\n"); +		recoverable = 0; +	} + +	if (reason & MCSR_TLBSYNC) +		printk("Simultaneous tlbsync operations\n"); + +	if (reason & MCSR_BSL2_ERR) { +		printk("Level 2 Cache Error\n"); +		recoverable = 0; +	} + +	if (reason & MCSR_MAV) { +		u64 addr; + +		addr = mfspr(SPRN_MCAR); +		addr |= (u64)mfspr(SPRN_MCARU) << 32; + +		printk("Machine Check %s Address: %#llx\n", +		       reason & MCSR_MEA ? "Effective" : "Physical", addr); +	} + +	mtspr(SPRN_MCSR, mcsr); +	return mfspr(SPRN_MCSR) == 0 && recoverable; +} +  int machine_check_e500(struct pt_regs *regs)  {  	unsigned long reason = get_mc_reason(regs);  |