| From dd496e47a5ad08cc26e8d4bfaeb3db59b1d1b033 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 10 Dec 2018 11:41:29 +0000 |
| Subject: powerpc/83xx: handle machine check caused by watchdog timer |
| |
| From: Christophe Leroy <christophe.leroy@c-s.fr> |
| |
| [ Upstream commit 0deae39cec6dab3a66794f3e9e83ca4dc30080f1 ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| arch/powerpc/include/asm/cputable.h | 1 + |
| arch/powerpc/include/asm/reg.h | 2 ++ |
| arch/powerpc/kernel/cputable.c | 10 ++++++---- |
| arch/powerpc/platforms/83xx/misc.c | 17 +++++++++++++++++ |
| 4 files changed, 26 insertions(+), 4 deletions(-) |
| |
| diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h |
| index 4e54282c29b44..cf51aea47510c 100644 |
| --- a/arch/powerpc/include/asm/cputable.h |
| +++ b/arch/powerpc/include/asm/cputable.h |
| @@ -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_47x(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_e500mc(void); |
| diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h |
| index ceb168cd3b814..26aeeaad32678 100644 |
| --- a/arch/powerpc/include/asm/reg.h |
| +++ b/arch/powerpc/include/asm/reg.h |
| @@ -663,6 +663,8 @@ |
| #define SRR1_PROGTRAP 0x00020000 /* Trap */ |
| #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_HSRR1 0x13B /* Save/Restore Register 1 */ |
| #define HSRR1_DENORM 0x00100000 /* Denorm exception */ |
| diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c |
| index 6a82ef039c509..7471ed48f41fa 100644 |
| --- a/arch/powerpc/kernel/cputable.c |
| +++ b/arch/powerpc/kernel/cputable.c |
| @@ -1162,6 +1162,7 @@ static struct cpu_spec __initdata cpu_specs[] = { |
| .machine_check = machine_check_generic, |
| .platform = "ppc603", |
| }, |
| +#ifdef CONFIG_PPC_83xx |
| { /* e300c1 (a 603e core, plus some) on 83xx */ |
| .pvr_mask = 0x7fff0000, |
| .pvr_value = 0x00830000, |
| @@ -1172,7 +1173,7 @@ static struct cpu_spec __initdata cpu_specs[] = { |
| .icache_bsize = 32, |
| .dcache_bsize = 32, |
| .cpu_setup = __setup_cpu_603, |
| - .machine_check = machine_check_generic, |
| + .machine_check = machine_check_83xx, |
| .platform = "ppc603", |
| }, |
| { /* e300c2 (an e300c1 core, plus some, minus FPU) on 83xx */ |
| @@ -1186,7 +1187,7 @@ static struct cpu_spec __initdata cpu_specs[] = { |
| .icache_bsize = 32, |
| .dcache_bsize = 32, |
| .cpu_setup = __setup_cpu_603, |
| - .machine_check = machine_check_generic, |
| + .machine_check = machine_check_83xx, |
| .platform = "ppc603", |
| }, |
| { /* e300c3 (e300c1, plus one IU, half cache size) on 83xx */ |
| @@ -1200,7 +1201,7 @@ static struct cpu_spec __initdata cpu_specs[] = { |
| .icache_bsize = 32, |
| .dcache_bsize = 32, |
| .cpu_setup = __setup_cpu_603, |
| - .machine_check = machine_check_generic, |
| + .machine_check = machine_check_83xx, |
| .num_pmcs = 4, |
| .oprofile_cpu_type = "ppc/e300", |
| .oprofile_type = PPC_OPROFILE_FSL_EMB, |
| @@ -1217,12 +1218,13 @@ static struct cpu_spec __initdata cpu_specs[] = { |
| .icache_bsize = 32, |
| .dcache_bsize = 32, |
| .cpu_setup = __setup_cpu_603, |
| - .machine_check = machine_check_generic, |
| + .machine_check = machine_check_83xx, |
| .num_pmcs = 4, |
| .oprofile_cpu_type = "ppc/e300", |
| .oprofile_type = PPC_OPROFILE_FSL_EMB, |
| .platform = "ppc603", |
| }, |
| +#endif |
| { /* default match, we assume split I/D cache & TB (non-601)... */ |
| .pvr_mask = 0x00000000, |
| .pvr_value = 0x00000000, |
| diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c |
| index d75c9816a5c92..2b6589fe812dd 100644 |
| --- a/arch/powerpc/platforms/83xx/misc.c |
| +++ b/arch/powerpc/platforms/83xx/misc.c |
| @@ -14,6 +14,7 @@ |
| #include <linux/of_platform.h> |
| #include <linux/pci.h> |
| |
| +#include <asm/debug.h> |
| #include <asm/io.h> |
| #include <asm/hw_irq.h> |
| #include <asm/ipic.h> |
| @@ -150,3 +151,19 @@ void __init mpc83xx_setup_arch(void) |
| |
| 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; |
| +} |
| -- |
| 2.20.1 |
| |