Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Christophe Leroy and committed by
Scott Wood
0deae39c 01f45c8f

+26 -4
+1
arch/powerpc/include/asm/cputable.h
··· 44 44 extern int machine_check_e200(struct pt_regs *regs); 45 45 extern int machine_check_47x(struct pt_regs *regs); 46 46 int machine_check_8xx(struct pt_regs *regs); 47 + int machine_check_83xx(struct pt_regs *regs); 47 48 48 49 extern void cpu_down_flush_e500v2(void); 49 50 extern void cpu_down_flush_e500mc(void);
+2
arch/powerpc/include/asm/reg.h
··· 769 769 #define SRR1_PROGTRAP 0x00020000 /* Trap */ 770 770 #define SRR1_PROGADDR 0x00010000 /* SRR0 contains subsequent addr */ 771 771 772 + #define SRR1_MCE_MCP 0x00080000 /* Machine check signal caused interrupt */ 773 + 772 774 #define SPRN_HSRR0 0x13A /* Save/Restore Register 0 */ 773 775 #define SPRN_HSRR1 0x13B /* Save/Restore Register 1 */ 774 776 #define HSRR1_DENORM 0x00100000 /* Denorm exception */
+6 -4
arch/powerpc/kernel/cputable.c
··· 1141 1141 .machine_check = machine_check_generic, 1142 1142 .platform = "ppc603", 1143 1143 }, 1144 + #ifdef CONFIG_PPC_83xx 1144 1145 { /* e300c1 (a 603e core, plus some) on 83xx */ 1145 1146 .pvr_mask = 0x7fff0000, 1146 1147 .pvr_value = 0x00830000, ··· 1152 1151 .icache_bsize = 32, 1153 1152 .dcache_bsize = 32, 1154 1153 .cpu_setup = __setup_cpu_603, 1155 - .machine_check = machine_check_generic, 1154 + .machine_check = machine_check_83xx, 1156 1155 .platform = "ppc603", 1157 1156 }, 1158 1157 { /* e300c2 (an e300c1 core, plus some, minus FPU) on 83xx */ ··· 1166 1165 .icache_bsize = 32, 1167 1166 .dcache_bsize = 32, 1168 1167 .cpu_setup = __setup_cpu_603, 1169 - .machine_check = machine_check_generic, 1168 + .machine_check = machine_check_83xx, 1170 1169 .platform = "ppc603", 1171 1170 }, 1172 1171 { /* e300c3 (e300c1, plus one IU, half cache size) on 83xx */ ··· 1180 1179 .icache_bsize = 32, 1181 1180 .dcache_bsize = 32, 1182 1181 .cpu_setup = __setup_cpu_603, 1183 - .machine_check = machine_check_generic, 1182 + .machine_check = machine_check_83xx, 1184 1183 .num_pmcs = 4, 1185 1184 .oprofile_cpu_type = "ppc/e300", 1186 1185 .oprofile_type = PPC_OPROFILE_FSL_EMB, ··· 1197 1196 .icache_bsize = 32, 1198 1197 .dcache_bsize = 32, 1199 1198 .cpu_setup = __setup_cpu_603, 1200 - .machine_check = machine_check_generic, 1199 + .machine_check = machine_check_83xx, 1201 1200 .num_pmcs = 4, 1202 1201 .oprofile_cpu_type = "ppc/e300", 1203 1202 .oprofile_type = PPC_OPROFILE_FSL_EMB, 1204 1203 .platform = "ppc603", 1205 1204 }, 1205 + #endif 1206 1206 { /* default match, we assume split I/D cache & TB (non-601)... */ 1207 1207 .pvr_mask = 0x00000000, 1208 1208 .pvr_value = 0x00000000,
+17
arch/powerpc/platforms/83xx/misc.c
··· 14 14 #include <linux/of_platform.h> 15 15 #include <linux/pci.h> 16 16 17 + #include <asm/debug.h> 17 18 #include <asm/io.h> 18 19 #include <asm/hw_irq.h> 19 20 #include <asm/ipic.h> ··· 150 149 ppc_md.progress("mpc83xx_setup_arch()", 0); 151 150 152 151 mpc83xx_setup_pci(); 152 + } 153 + 154 + int machine_check_83xx(struct pt_regs *regs) 155 + { 156 + u32 mask = 1 << (31 - IPIC_MCP_WDT); 157 + 158 + if (!(regs->msr & SRR1_MCE_MCP) || !(ipic_get_mcp_status() & mask)) 159 + return machine_check_generic(regs); 160 + ipic_clear_mcp_status(mask); 161 + 162 + if (debugger_fault_handler(regs)) 163 + return 1; 164 + 165 + die("Watchdog NMI Reset", regs, 0); 166 + 167 + return 1; 153 168 }