Commit 0deae39c authored by Christophe Leroy's avatar Christophe Leroy Committed by Scott Wood
Browse files

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: default avatarChristophe Leroy <christophe.leroy@c-s.fr>
[scottwood: added missing #include]
Signed-off-by: default avatarScott Wood <oss@buserror.net>
parent 01f45c8f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -769,6 +769,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 */
+6 −4
Original line number Diff line number Diff line
@@ -1141,6 +1141,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,
@@ -1151,7 +1152,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 */
@@ -1165,7 +1166,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 */
@@ -1179,7 +1180,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,
@@ -1196,12 +1197,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,
+17 −0
Original line number Diff line number Diff line
@@ -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;
}