powerpc/83xx: handle machine check caused by watchdog timer
When the watchdog timer is set in interrupt mode, it causes a machine check when it times out. The purpose of this mode is to ease debugging, not to crash the kernel and reboot the machine. This patch implements a special handling for that, in order to not crash the kernel if the watchdog times out while in interrupt or within the idle task. Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> [scottwood: added missing #include] Signed-off-by: Scott Wood <oss@buserror.net>
This commit is contained in:
Родитель
01f45c8fb8
Коммит
0deae39cec
|
@ -44,6 +44,7 @@ extern int machine_check_e500(struct pt_regs *regs);
|
||||||
extern int machine_check_e200(struct pt_regs *regs);
|
extern int machine_check_e200(struct pt_regs *regs);
|
||||||
extern int machine_check_47x(struct pt_regs *regs);
|
extern int machine_check_47x(struct pt_regs *regs);
|
||||||
int machine_check_8xx(struct pt_regs *regs);
|
int machine_check_8xx(struct pt_regs *regs);
|
||||||
|
int machine_check_83xx(struct pt_regs *regs);
|
||||||
|
|
||||||
extern void cpu_down_flush_e500v2(void);
|
extern void cpu_down_flush_e500v2(void);
|
||||||
extern void cpu_down_flush_e500mc(void);
|
extern void cpu_down_flush_e500mc(void);
|
||||||
|
|
|
@ -769,6 +769,8 @@
|
||||||
#define SRR1_PROGTRAP 0x00020000 /* Trap */
|
#define SRR1_PROGTRAP 0x00020000 /* Trap */
|
||||||
#define SRR1_PROGADDR 0x00010000 /* SRR0 contains subsequent addr */
|
#define SRR1_PROGADDR 0x00010000 /* SRR0 contains subsequent addr */
|
||||||
|
|
||||||
|
#define SRR1_MCE_MCP 0x00080000 /* Machine check signal caused interrupt */
|
||||||
|
|
||||||
#define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */
|
#define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */
|
||||||
#define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */
|
#define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */
|
||||||
#define HSRR1_DENORM 0x00100000 /* Denorm exception */
|
#define HSRR1_DENORM 0x00100000 /* Denorm exception */
|
||||||
|
|
|
@ -1141,6 +1141,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
||||||
.machine_check = machine_check_generic,
|
.machine_check = machine_check_generic,
|
||||||
.platform = "ppc603",
|
.platform = "ppc603",
|
||||||
},
|
},
|
||||||
|
#ifdef CONFIG_PPC_83xx
|
||||||
{ /* e300c1 (a 603e core, plus some) on 83xx */
|
{ /* e300c1 (a 603e core, plus some) on 83xx */
|
||||||
.pvr_mask = 0x7fff0000,
|
.pvr_mask = 0x7fff0000,
|
||||||
.pvr_value = 0x00830000,
|
.pvr_value = 0x00830000,
|
||||||
|
@ -1151,7 +1152,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
||||||
.icache_bsize = 32,
|
.icache_bsize = 32,
|
||||||
.dcache_bsize = 32,
|
.dcache_bsize = 32,
|
||||||
.cpu_setup = __setup_cpu_603,
|
.cpu_setup = __setup_cpu_603,
|
||||||
.machine_check = machine_check_generic,
|
.machine_check = machine_check_83xx,
|
||||||
.platform = "ppc603",
|
.platform = "ppc603",
|
||||||
},
|
},
|
||||||
{ /* e300c2 (an e300c1 core, plus some, minus FPU) on 83xx */
|
{ /* e300c2 (an e300c1 core, plus some, minus FPU) on 83xx */
|
||||||
|
@ -1165,7 +1166,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
||||||
.icache_bsize = 32,
|
.icache_bsize = 32,
|
||||||
.dcache_bsize = 32,
|
.dcache_bsize = 32,
|
||||||
.cpu_setup = __setup_cpu_603,
|
.cpu_setup = __setup_cpu_603,
|
||||||
.machine_check = machine_check_generic,
|
.machine_check = machine_check_83xx,
|
||||||
.platform = "ppc603",
|
.platform = "ppc603",
|
||||||
},
|
},
|
||||||
{ /* e300c3 (e300c1, plus one IU, half cache size) on 83xx */
|
{ /* e300c3 (e300c1, plus one IU, half cache size) on 83xx */
|
||||||
|
@ -1179,7 +1180,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
||||||
.icache_bsize = 32,
|
.icache_bsize = 32,
|
||||||
.dcache_bsize = 32,
|
.dcache_bsize = 32,
|
||||||
.cpu_setup = __setup_cpu_603,
|
.cpu_setup = __setup_cpu_603,
|
||||||
.machine_check = machine_check_generic,
|
.machine_check = machine_check_83xx,
|
||||||
.num_pmcs = 4,
|
.num_pmcs = 4,
|
||||||
.oprofile_cpu_type = "ppc/e300",
|
.oprofile_cpu_type = "ppc/e300",
|
||||||
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||||
|
@ -1196,12 +1197,13 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
||||||
.icache_bsize = 32,
|
.icache_bsize = 32,
|
||||||
.dcache_bsize = 32,
|
.dcache_bsize = 32,
|
||||||
.cpu_setup = __setup_cpu_603,
|
.cpu_setup = __setup_cpu_603,
|
||||||
.machine_check = machine_check_generic,
|
.machine_check = machine_check_83xx,
|
||||||
.num_pmcs = 4,
|
.num_pmcs = 4,
|
||||||
.oprofile_cpu_type = "ppc/e300",
|
.oprofile_cpu_type = "ppc/e300",
|
||||||
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||||
.platform = "ppc603",
|
.platform = "ppc603",
|
||||||
},
|
},
|
||||||
|
#endif
|
||||||
{ /* default match, we assume split I/D cache & TB (non-601)... */
|
{ /* default match, we assume split I/D cache & TB (non-601)... */
|
||||||
.pvr_mask = 0x00000000,
|
.pvr_mask = 0x00000000,
|
||||||
.pvr_value = 0x00000000,
|
.pvr_value = 0x00000000,
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
|
|
||||||
|
#include <asm/debug.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/hw_irq.h>
|
#include <asm/hw_irq.h>
|
||||||
#include <asm/ipic.h>
|
#include <asm/ipic.h>
|
||||||
|
@ -150,3 +151,19 @@ void __init mpc83xx_setup_arch(void)
|
||||||
|
|
||||||
mpc83xx_setup_pci();
|
mpc83xx_setup_pci();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int machine_check_83xx(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
u32 mask = 1 << (31 - IPIC_MCP_WDT);
|
||||||
|
|
||||||
|
if (!(regs->msr & SRR1_MCE_MCP) || !(ipic_get_mcp_status() & mask))
|
||||||
|
return machine_check_generic(regs);
|
||||||
|
ipic_clear_mcp_status(mask);
|
||||||
|
|
||||||
|
if (debugger_fault_handler(regs))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
die("Watchdog NMI Reset", regs, 0);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче