diff options
author | Scott Wood <scottwood@freescale.com> | 2010-04-08 01:38:22 -0400 |
---|---|---|
committer | Kumar Gala <galak@kernel.crashing.org> | 2010-05-21 08:41:52 -0400 |
commit | fe04b1121511a97982a1fcdd38e44d2029304a6d (patch) | |
tree | 665804df54ee2b082ecfad5fb898f4f4d0a443c8 /arch/powerpc | |
parent | 99ec28f183daa450faa7bdad6f932364ae325648 (diff) |
powerpc/e500mc: Implement machine check handler.
Most of the MSCR bit assigments are different in e500mc versus
e500, and they are now write-one-to-clear.
Some e500mc machine check conditions are made recoverable (as long as
they aren't stuck on), most notably L1 instruction cache parity errors.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/cputable.h | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/reg_booke.h | 33 | ||||
-rw-r--r-- | arch/powerpc/kernel/cputable.c | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/traps.c | 88 |
4 files changed, 112 insertions, 12 deletions
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index e3cba4e1eb34..b0b21134f61a 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h | |||
@@ -70,6 +70,7 @@ struct pt_regs; | |||
70 | extern int machine_check_generic(struct pt_regs *regs); | 70 | extern int machine_check_generic(struct pt_regs *regs); |
71 | extern int machine_check_4xx(struct pt_regs *regs); | 71 | extern int machine_check_4xx(struct pt_regs *regs); |
72 | extern int machine_check_440A(struct pt_regs *regs); | 72 | extern int machine_check_440A(struct pt_regs *regs); |
73 | extern int machine_check_e500mc(struct pt_regs *regs); | ||
73 | extern int machine_check_e500(struct pt_regs *regs); | 74 | extern int machine_check_e500(struct pt_regs *regs); |
74 | extern int machine_check_e200(struct pt_regs *regs); | 75 | extern int machine_check_e200(struct pt_regs *regs); |
75 | extern int machine_check_47x(struct pt_regs *regs); | 76 | extern int machine_check_47x(struct pt_regs *regs); |
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 5304a37ba425..2360317179a9 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h | |||
@@ -4,6 +4,12 @@ | |||
4 | * are not true Book E PowerPCs, they borrowed a number of features | 4 | * are not true Book E PowerPCs, they borrowed a number of features |
5 | * before Book E was finalized, and are included here as well. Unfortunatly, | 5 | * before Book E was finalized, and are included here as well. Unfortunatly, |
6 | * they sometimes used different locations than true Book E CPUs did. | 6 | * they sometimes used different locations than true Book E CPUs did. |
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version 2 | ||
10 | * as published by the Free Software Foundation. | ||
11 | * | ||
12 | * Copyright 2009-2010 Freescale Semiconductor, Inc. | ||
7 | */ | 13 | */ |
8 | #ifdef __KERNEL__ | 14 | #ifdef __KERNEL__ |
9 | #ifndef __ASM_POWERPC_REG_BOOKE_H__ | 15 | #ifndef __ASM_POWERPC_REG_BOOKE_H__ |
@@ -88,6 +94,7 @@ | |||
88 | #define SPRN_IVOR35 0x213 /* Interrupt Vector Offset Register 35 */ | 94 | #define SPRN_IVOR35 0x213 /* Interrupt Vector Offset Register 35 */ |
89 | #define SPRN_IVOR36 0x214 /* Interrupt Vector Offset Register 36 */ | 95 | #define SPRN_IVOR36 0x214 /* Interrupt Vector Offset Register 36 */ |
90 | #define SPRN_IVOR37 0x215 /* Interrupt Vector Offset Register 37 */ | 96 | #define SPRN_IVOR37 0x215 /* Interrupt Vector Offset Register 37 */ |
97 | #define SPRN_MCARU 0x239 /* Machine Check Address Register Upper */ | ||
91 | #define SPRN_MCSRR0 0x23A /* Machine Check Save and Restore Register 0 */ | 98 | #define SPRN_MCSRR0 0x23A /* Machine Check Save and Restore Register 0 */ |
92 | #define SPRN_MCSRR1 0x23B /* Machine Check Save and Restore Register 1 */ | 99 | #define SPRN_MCSRR1 0x23B /* Machine Check Save and Restore Register 1 */ |
93 | #define SPRN_MCSR 0x23C /* Machine Check Status Register */ | 100 | #define SPRN_MCSR 0x23C /* Machine Check Status Register */ |
@@ -196,8 +203,11 @@ | |||
196 | #define PPC47x_MCSR_IPR 0x00400000 /* Imprecise Machine Check Exception */ | 203 | #define PPC47x_MCSR_IPR 0x00400000 /* Imprecise Machine Check Exception */ |
197 | 204 | ||
198 | #ifdef CONFIG_E500 | 205 | #ifdef CONFIG_E500 |
206 | /* All e500 */ | ||
199 | #define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */ | 207 | #define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */ |
200 | #define MCSR_ICPERR 0x40000000UL /* I-Cache Parity Error */ | 208 | #define MCSR_ICPERR 0x40000000UL /* I-Cache Parity Error */ |
209 | |||
210 | /* e500v1/v2 */ | ||
201 | #define MCSR_DCP_PERR 0x20000000UL /* D-Cache Push Parity Error */ | 211 | #define MCSR_DCP_PERR 0x20000000UL /* D-Cache Push Parity Error */ |
202 | #define MCSR_DCPERR 0x10000000UL /* D-Cache Parity Error */ | 212 | #define MCSR_DCPERR 0x10000000UL /* D-Cache Parity Error */ |
203 | #define MCSR_BUS_IAERR 0x00000080UL /* Instruction Address Error */ | 213 | #define MCSR_BUS_IAERR 0x00000080UL /* Instruction Address Error */ |
@@ -209,12 +219,20 @@ | |||
209 | #define MCSR_BUS_IPERR 0x00000002UL /* Instruction parity Error */ | 219 | #define MCSR_BUS_IPERR 0x00000002UL /* Instruction parity Error */ |
210 | #define MCSR_BUS_RPERR 0x00000001UL /* Read parity Error */ | 220 | #define MCSR_BUS_RPERR 0x00000001UL /* Read parity Error */ |
211 | 221 | ||
212 | /* e500 parts may set unused bits in MCSR; mask these off */ | 222 | /* e500mc */ |
213 | #define MCSR_MASK (MCSR_MCP | MCSR_ICPERR | MCSR_DCP_PERR | \ | 223 | #define MCSR_DCPERR_MC 0x20000000UL /* D-Cache Parity Error */ |
214 | MCSR_DCPERR | MCSR_BUS_IAERR | MCSR_BUS_RAERR | \ | 224 | #define MCSR_L2MMU_MHIT 0x04000000UL /* Hit on multiple TLB entries */ |
215 | MCSR_BUS_WAERR | MCSR_BUS_IBERR | MCSR_BUS_RBERR | \ | 225 | #define MCSR_NMI 0x00100000UL /* Non-Maskable Interrupt */ |
216 | MCSR_BUS_WBERR | MCSR_BUS_IPERR | MCSR_BUS_RPERR) | 226 | #define MCSR_MAV 0x00080000UL /* MCAR address valid */ |
227 | #define MCSR_MEA 0x00040000UL /* MCAR is effective address */ | ||
228 | #define MCSR_IF 0x00010000UL /* Instruction Fetch */ | ||
229 | #define MCSR_LD 0x00008000UL /* Load */ | ||
230 | #define MCSR_ST 0x00004000UL /* Store */ | ||
231 | #define MCSR_LDG 0x00002000UL /* Guarded Load */ | ||
232 | #define MCSR_TLBSYNC 0x00000002UL /* Multiple tlbsyncs detected */ | ||
233 | #define MCSR_BSL2_ERR 0x00000001UL /* Backside L2 cache error */ | ||
217 | #endif | 234 | #endif |
235 | |||
218 | #ifdef CONFIG_E200 | 236 | #ifdef CONFIG_E200 |
219 | #define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */ | 237 | #define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */ |
220 | #define MCSR_CP_PERR 0x20000000UL /* Cache Push Parity Error */ | 238 | #define MCSR_CP_PERR 0x20000000UL /* Cache Push Parity Error */ |
@@ -225,11 +243,6 @@ | |||
225 | #define MCSR_BUS_DRERR 0x00000008UL /* Read Bus Error on data load */ | 243 | #define MCSR_BUS_DRERR 0x00000008UL /* Read Bus Error on data load */ |
226 | #define MCSR_BUS_WRERR 0x00000004UL /* Write Bus Error on buffered | 244 | #define MCSR_BUS_WRERR 0x00000004UL /* Write Bus Error on buffered |
227 | store or cache line push */ | 245 | store or cache line push */ |
228 | |||
229 | /* e200 parts may set unused bits in MCSR; mask these off */ | ||
230 | #define MCSR_MASK (MCSR_MCP | MCSR_CP_PERR | MCSR_CPERR | \ | ||
231 | MCSR_EXCP_ERR | MCSR_BUS_IRERR | MCSR_BUS_DRERR | \ | ||
232 | MCSR_BUS_WRERR) | ||
233 | #endif | 246 | #endif |
234 | 247 | ||
235 | /* Bit definitions for the DBSR. */ | 248 | /* Bit definitions for the DBSR. */ |
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 9556be903e96..87aa0f3c6047 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -1840,7 +1840,7 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
1840 | .oprofile_cpu_type = "ppc/e500mc", | 1840 | .oprofile_cpu_type = "ppc/e500mc", |
1841 | .oprofile_type = PPC_OPROFILE_FSL_EMB, | 1841 | .oprofile_type = PPC_OPROFILE_FSL_EMB, |
1842 | .cpu_setup = __setup_cpu_e500mc, | 1842 | .cpu_setup = __setup_cpu_e500mc, |
1843 | .machine_check = machine_check_e500, | 1843 | .machine_check = machine_check_e500mc, |
1844 | .platform = "ppce500mc", | 1844 | .platform = "ppce500mc", |
1845 | }, | 1845 | }, |
1846 | { /* default match */ | 1846 | { /* default match */ |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index ca7ce85ebc2e..5ed46758f4e9 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | 2 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) |
3 | * Copyright 2007-2010 Freescale Semiconductor, Inc. | ||
3 | * | 4 | * |
4 | * This program is free software; you can redistribute it and/or | 5 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License | 6 | * 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) | |||
305 | #ifndef CONFIG_FSL_BOOKE | 306 | #ifndef CONFIG_FSL_BOOKE |
306 | #define get_mc_reason(regs) ((regs)->dsisr) | 307 | #define get_mc_reason(regs) ((regs)->dsisr) |
307 | #else | 308 | #else |
308 | #define get_mc_reason(regs) (mfspr(SPRN_MCSR) & MCSR_MASK) | 309 | #define get_mc_reason(regs) (mfspr(SPRN_MCSR)) |
309 | #endif | 310 | #endif |
310 | #define REASON_FP ESR_FP | 311 | #define REASON_FP ESR_FP |
311 | #define REASON_ILLEGAL (ESR_PIL | ESR_PUO) | 312 | #define REASON_ILLEGAL (ESR_PIL | ESR_PUO) |
@@ -421,6 +422,91 @@ int machine_check_47x(struct pt_regs *regs) | |||
421 | return 0; | 422 | return 0; |
422 | } | 423 | } |
423 | #elif defined(CONFIG_E500) | 424 | #elif defined(CONFIG_E500) |
425 | int machine_check_e500mc(struct pt_regs *regs) | ||
426 | { | ||
427 | unsigned long mcsr = mfspr(SPRN_MCSR); | ||
428 | unsigned long reason = mcsr; | ||
429 | int recoverable = 1; | ||
430 | |||
431 | printk("Machine check in kernel mode.\n"); | ||
432 | printk("Caused by (from MCSR=%lx): ", reason); | ||
433 | |||
434 | if (reason & MCSR_MCP) | ||
435 | printk("Machine Check Signal\n"); | ||
436 | |||
437 | if (reason & MCSR_ICPERR) { | ||
438 | printk("Instruction Cache Parity Error\n"); | ||
439 | |||
440 | /* | ||
441 | * This is recoverable by invalidating the i-cache. | ||
442 | */ | ||
443 | mtspr(SPRN_L1CSR1, mfspr(SPRN_L1CSR1) | L1CSR1_ICFI); | ||
444 | while (mfspr(SPRN_L1CSR1) & L1CSR1_ICFI) | ||
445 | ; | ||
446 | |||
447 | /* | ||
448 | * This will generally be accompanied by an instruction | ||
449 | * fetch error report -- only treat MCSR_IF as fatal | ||
450 | * if it wasn't due to an L1 parity error. | ||
451 | */ | ||
452 | reason &= ~MCSR_IF; | ||
453 | } | ||
454 | |||
455 | if (reason & MCSR_DCPERR_MC) { | ||
456 | printk("Data Cache Parity Error\n"); | ||
457 | recoverable = 0; | ||
458 | } | ||
459 | |||
460 | if (reason & MCSR_L2MMU_MHIT) { | ||
461 | printk("Hit on multiple TLB entries\n"); | ||
462 | recoverable = 0; | ||
463 | } | ||
464 | |||
465 | if (reason & MCSR_NMI) | ||
466 | printk("Non-maskable interrupt\n"); | ||
467 | |||
468 | if (reason & MCSR_IF) { | ||
469 | printk("Instruction Fetch Error Report\n"); | ||
470 | recoverable = 0; | ||
471 | } | ||
472 | |||
473 | if (reason & MCSR_LD) { | ||
474 | printk("Load Error Report\n"); | ||
475 | recoverable = 0; | ||
476 | } | ||
477 | |||
478 | if (reason & MCSR_ST) { | ||
479 | printk("Store Error Report\n"); | ||
480 | recoverable = 0; | ||
481 | } | ||
482 | |||
483 | if (reason & MCSR_LDG) { | ||
484 | printk("Guarded Load Error Report\n"); | ||
485 | recoverable = 0; | ||
486 | } | ||
487 | |||
488 | if (reason & MCSR_TLBSYNC) | ||
489 | printk("Simultaneous tlbsync operations\n"); | ||
490 | |||
491 | if (reason & MCSR_BSL2_ERR) { | ||
492 | printk("Level 2 Cache Error\n"); | ||
493 | recoverable = 0; | ||
494 | } | ||
495 | |||
496 | if (reason & MCSR_MAV) { | ||
497 | u64 addr; | ||
498 | |||
499 | addr = mfspr(SPRN_MCAR); | ||
500 | addr |= (u64)mfspr(SPRN_MCARU) << 32; | ||
501 | |||
502 | printk("Machine Check %s Address: %#llx\n", | ||
503 | reason & MCSR_MEA ? "Effective" : "Physical", addr); | ||
504 | } | ||
505 | |||
506 | mtspr(SPRN_MCSR, mcsr); | ||
507 | return mfspr(SPRN_MCSR) == 0 && recoverable; | ||
508 | } | ||
509 | |||
424 | int machine_check_e500(struct pt_regs *regs) | 510 | int machine_check_e500(struct pt_regs *regs) |
425 | { | 511 | { |
426 | unsigned long reason = get_mc_reason(regs); | 512 | unsigned long reason = get_mc_reason(regs); |