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:
Christophe Leroy 2018-12-10 11:41:29 +00:00 коммит произвёл Scott Wood
Родитель 01f45c8fb8
Коммит 0deae39cec
4 изменённых файлов: 26 добавлений и 4 удалений

Просмотреть файл

@ -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;
}