aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc/kernel/traps.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-12-20 23:39:21 -0500
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>2007-12-23 14:11:59 -0500
commit47c0bd1ae24c34e851cf0f2b02ef2a6847d7ae15 (patch)
tree86fab68618a4afa03660cc576c9e7da3e5a0b520 /arch/ppc/kernel/traps.c
parentc2a7dcad9f0d92d7a96e735abb8bec7b9c621536 (diff)
[POWERPC] Reworking machine check handling and Fix 440/440A
This adds a cputable function pointer for the CPU-side machine check handling. The semantic is still the same as the old one, the one in ppc_md. overrides the one in cputable, though ultimately we'll want to change that so the CPU gets first. This removes CONFIG_440A which was a problem for multiplatform kernels and instead fixes up the IVOR at runtime from a setup_cpu function. The "A" version of the machine check also tweaks the regs->trap value to differenciate the 2 versions at the C level. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'arch/ppc/kernel/traps.c')
-rw-r--r--arch/ppc/kernel/traps.c98
1 files changed, 67 insertions, 31 deletions
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index c78568905c3b..25a1085fbd01 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -231,39 +231,25 @@ platform_machine_check(struct pt_regs *regs)
231{ 231{
232} 232}
233 233
234void machine_check_exception(struct pt_regs *regs) 234#if defined(CONFIG_4xx)
235int machine_check_4xx(struct pt_regs *regs)
235{ 236{
236 unsigned long reason = get_mc_reason(regs); 237 unsigned long reason = get_mc_reason(regs);
237 238
238 if (user_mode(regs)) {
239 regs->msr |= MSR_RI;
240 _exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
241 return;
242 }
243
244#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
245 /* the qspan pci read routines can cause machine checks -- Cort */
246 bad_page_fault(regs, regs->dar, SIGBUS);
247 return;
248#endif
249
250 if (debugger_fault_handler) {
251 debugger_fault_handler(regs);
252 regs->msr |= MSR_RI;
253 return;
254 }
255
256 if (check_io_access(regs))
257 return;
258
259#if defined(CONFIG_4xx) && !defined(CONFIG_440A)
260 if (reason & ESR_IMCP) { 239 if (reason & ESR_IMCP) {
261 printk("Instruction"); 240 printk("Instruction");
262 mtspr(SPRN_ESR, reason & ~ESR_IMCP); 241 mtspr(SPRN_ESR, reason & ~ESR_IMCP);
263 } else 242 } else
264 printk("Data"); 243 printk("Data");
265 printk(" machine check in kernel mode.\n"); 244 printk(" machine check in kernel mode.\n");
266#elif defined(CONFIG_440A) 245
246 return 0;
247}
248
249int machine_check_440A(struct pt_regs *regs)
250{
251 unsigned long reason = get_mc_reason(regs);
252
267 printk("Machine check in kernel mode.\n"); 253 printk("Machine check in kernel mode.\n");
268 if (reason & ESR_IMCP){ 254 if (reason & ESR_IMCP){
269 printk("Instruction Synchronous Machine Check exception\n"); 255 printk("Instruction Synchronous Machine Check exception\n");
@@ -293,7 +279,13 @@ void machine_check_exception(struct pt_regs *regs)
293 /* Clear MCSR */ 279 /* Clear MCSR */
294 mtspr(SPRN_MCSR, mcsr); 280 mtspr(SPRN_MCSR, mcsr);
295 } 281 }
296#elif defined (CONFIG_E500) 282 return 0;
283}
284#elif defined(CONFIG_E500)
285int machine_check_e500(struct pt_regs *regs)
286{
287 unsigned long reason = get_mc_reason(regs);
288
297 printk("Machine check in kernel mode.\n"); 289 printk("Machine check in kernel mode.\n");
298 printk("Caused by (from MCSR=%lx): ", reason); 290 printk("Caused by (from MCSR=%lx): ", reason);
299 291
@@ -305,8 +297,6 @@ void machine_check_exception(struct pt_regs *regs)
305 printk("Data Cache Push Parity Error\n"); 297 printk("Data Cache Push Parity Error\n");
306 if (reason & MCSR_DCPERR) 298 if (reason & MCSR_DCPERR)
307 printk("Data Cache Parity Error\n"); 299 printk("Data Cache Parity Error\n");
308 if (reason & MCSR_GL_CI)
309 printk("Guarded Load or Cache-Inhibited stwcx.\n");
310 if (reason & MCSR_BUS_IAERR) 300 if (reason & MCSR_BUS_IAERR)
311 printk("Bus - Instruction Address Error\n"); 301 printk("Bus - Instruction Address Error\n");
312 if (reason & MCSR_BUS_RAERR) 302 if (reason & MCSR_BUS_RAERR)
@@ -318,12 +308,19 @@ void machine_check_exception(struct pt_regs *regs)
318 if (reason & MCSR_BUS_RBERR) 308 if (reason & MCSR_BUS_RBERR)
319 printk("Bus - Read Data Bus Error\n"); 309 printk("Bus - Read Data Bus Error\n");
320 if (reason & MCSR_BUS_WBERR) 310 if (reason & MCSR_BUS_WBERR)
321 printk("Bus - Write Data Bus Error\n"); 311 printk("Bus - Read Data Bus Error\n");
322 if (reason & MCSR_BUS_IPERR) 312 if (reason & MCSR_BUS_IPERR)
323 printk("Bus - Instruction Parity Error\n"); 313 printk("Bus - Instruction Parity Error\n");
324 if (reason & MCSR_BUS_RPERR) 314 if (reason & MCSR_BUS_RPERR)
325 printk("Bus - Read Parity Error\n"); 315 printk("Bus - Read Parity Error\n");
326#elif defined (CONFIG_E200) 316
317 return 0;
318}
319#elif defined(CONFIG_E200)
320int machine_check_e200(struct pt_regs *regs)
321{
322 unsigned long reason = get_mc_reason(regs);
323
327 printk("Machine check in kernel mode.\n"); 324 printk("Machine check in kernel mode.\n");
328 printk("Caused by (from MCSR=%lx): ", reason); 325 printk("Caused by (from MCSR=%lx): ", reason);
329 326
@@ -341,7 +338,14 @@ void machine_check_exception(struct pt_regs *regs)
341 printk("Bus - Read Bus Error on data load\n"); 338 printk("Bus - Read Bus Error on data load\n");
342 if (reason & MCSR_BUS_WRERR) 339 if (reason & MCSR_BUS_WRERR)
343 printk("Bus - Write Bus Error on buffered store or cache line push\n"); 340 printk("Bus - Write Bus Error on buffered store or cache line push\n");
344#else /* !CONFIG_4xx && !CONFIG_E500 && !CONFIG_E200 */ 341
342 return 0;
343}
344#else
345int machine_check_generic(struct pt_regs *regs)
346{
347 unsigned long reason = get_mc_reason(regs);
348
345 printk("Machine check in kernel mode.\n"); 349 printk("Machine check in kernel mode.\n");
346 printk("Caused by (from SRR1=%lx): ", reason); 350 printk("Caused by (from SRR1=%lx): ", reason);
347 switch (reason & 0x601F0000) { 351 switch (reason & 0x601F0000) {
@@ -371,7 +375,39 @@ void machine_check_exception(struct pt_regs *regs)
371 default: 375 default:
372 printk("Unknown values in msr\n"); 376 printk("Unknown values in msr\n");
373 } 377 }
374#endif /* CONFIG_4xx */ 378 return 0;
379}
380#endif /* everything else */
381
382void machine_check_exception(struct pt_regs *regs)
383{
384 int recover = 0;
385
386 if (cur_cpu_spec->machine_check)
387 recover = cur_cpu_spec->machine_check(regs);
388 if (recover > 0)
389 return;
390
391 if (user_mode(regs)) {
392 regs->msr |= MSR_RI;
393 _exception(SIGBUS, regs, BUS_ADRERR, regs->nip);
394 return;
395 }
396
397#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
398 /* the qspan pci read routines can cause machine checks -- Cort */
399 bad_page_fault(regs, regs->dar, SIGBUS);
400 return;
401#endif
402
403 if (debugger_fault_handler) {
404 debugger_fault_handler(regs);
405 regs->msr |= MSR_RI;
406 return;
407 }
408
409 if (check_io_access(regs))
410 return;
375 411
376 /* 412 /*
377 * Optional platform-provided routine to print out 413 * Optional platform-provided routine to print out