diff options
Diffstat (limited to 'arch/powerpc/kernel/crash.c')
-rw-r--r-- | arch/powerpc/kernel/crash.c | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 6f4613dd05e..417f7b05a9c 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
25 | #include <linux/irq.h> | 25 | #include <linux/irq.h> |
26 | #include <linux/types.h> | 26 | #include <linux/types.h> |
27 | #include <linux/lmb.h> | 27 | #include <linux/memblock.h> |
28 | 28 | ||
29 | #include <asm/processor.h> | 29 | #include <asm/processor.h> |
30 | #include <asm/machdep.h> | 30 | #include <asm/machdep.h> |
@@ -162,6 +162,34 @@ static void crash_kexec_prepare_cpus(int cpu) | |||
162 | /* Leave the IPI callback set */ | 162 | /* Leave the IPI callback set */ |
163 | } | 163 | } |
164 | 164 | ||
165 | /* wait for all the CPUs to hit real mode but timeout if they don't come in */ | ||
166 | #ifdef CONFIG_PPC_STD_MMU_64 | ||
167 | static void crash_kexec_wait_realmode(int cpu) | ||
168 | { | ||
169 | unsigned int msecs; | ||
170 | int i; | ||
171 | |||
172 | msecs = 10000; | ||
173 | for (i=0; i < NR_CPUS && msecs > 0; i++) { | ||
174 | if (i == cpu) | ||
175 | continue; | ||
176 | |||
177 | while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) { | ||
178 | barrier(); | ||
179 | if (!cpu_possible(i)) { | ||
180 | break; | ||
181 | } | ||
182 | if (!cpu_online(i)) { | ||
183 | break; | ||
184 | } | ||
185 | msecs--; | ||
186 | mdelay(1); | ||
187 | } | ||
188 | } | ||
189 | mb(); | ||
190 | } | ||
191 | #endif | ||
192 | |||
165 | /* | 193 | /* |
166 | * This function will be called by secondary cpus or by kexec cpu | 194 | * This function will be called by secondary cpus or by kexec cpu |
167 | * if soft-reset is activated to stop some CPUs. | 195 | * if soft-reset is activated to stop some CPUs. |
@@ -347,10 +375,12 @@ int crash_shutdown_unregister(crash_shutdown_t handler) | |||
347 | EXPORT_SYMBOL(crash_shutdown_unregister); | 375 | EXPORT_SYMBOL(crash_shutdown_unregister); |
348 | 376 | ||
349 | static unsigned long crash_shutdown_buf[JMP_BUF_LEN]; | 377 | static unsigned long crash_shutdown_buf[JMP_BUF_LEN]; |
378 | static int crash_shutdown_cpu = -1; | ||
350 | 379 | ||
351 | static int handle_fault(struct pt_regs *regs) | 380 | static int handle_fault(struct pt_regs *regs) |
352 | { | 381 | { |
353 | longjmp(crash_shutdown_buf, 1); | 382 | if (crash_shutdown_cpu == smp_processor_id()) |
383 | longjmp(crash_shutdown_buf, 1); | ||
354 | return 0; | 384 | return 0; |
355 | } | 385 | } |
356 | 386 | ||
@@ -375,11 +405,14 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
375 | for_each_irq(i) { | 405 | for_each_irq(i) { |
376 | struct irq_desc *desc = irq_to_desc(i); | 406 | struct irq_desc *desc = irq_to_desc(i); |
377 | 407 | ||
408 | if (!desc || !desc->chip || !desc->chip->eoi) | ||
409 | continue; | ||
410 | |||
378 | if (desc->status & IRQ_INPROGRESS) | 411 | if (desc->status & IRQ_INPROGRESS) |
379 | desc->chip->eoi(i); | 412 | desc->chip->eoi(i); |
380 | 413 | ||
381 | if (!(desc->status & IRQ_DISABLED)) | 414 | if (!(desc->status & IRQ_DISABLED)) |
382 | desc->chip->disable(i); | 415 | desc->chip->shutdown(i); |
383 | } | 416 | } |
384 | 417 | ||
385 | /* | 418 | /* |
@@ -388,6 +421,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
388 | */ | 421 | */ |
389 | old_handler = __debugger_fault_handler; | 422 | old_handler = __debugger_fault_handler; |
390 | __debugger_fault_handler = handle_fault; | 423 | __debugger_fault_handler = handle_fault; |
424 | crash_shutdown_cpu = smp_processor_id(); | ||
391 | for (i = 0; crash_shutdown_handles[i]; i++) { | 425 | for (i = 0; crash_shutdown_handles[i]; i++) { |
392 | if (setjmp(crash_shutdown_buf) == 0) { | 426 | if (setjmp(crash_shutdown_buf) == 0) { |
393 | /* | 427 | /* |
@@ -401,6 +435,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
401 | asm volatile("sync; isync"); | 435 | asm volatile("sync; isync"); |
402 | } | 436 | } |
403 | } | 437 | } |
438 | crash_shutdown_cpu = -1; | ||
404 | __debugger_fault_handler = old_handler; | 439 | __debugger_fault_handler = old_handler; |
405 | 440 | ||
406 | /* | 441 | /* |
@@ -412,6 +447,9 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
412 | crash_kexec_prepare_cpus(crashing_cpu); | 447 | crash_kexec_prepare_cpus(crashing_cpu); |
413 | cpu_set(crashing_cpu, cpus_in_crash); | 448 | cpu_set(crashing_cpu, cpus_in_crash); |
414 | crash_kexec_stop_spus(); | 449 | crash_kexec_stop_spus(); |
450 | #if defined(CONFIG_PPC_STD_MMU_64) && defined(CONFIG_SMP) | ||
451 | crash_kexec_wait_realmode(crashing_cpu); | ||
452 | #endif | ||
415 | if (ppc_md.kexec_cpu_down) | 453 | if (ppc_md.kexec_cpu_down) |
416 | ppc_md.kexec_cpu_down(1, 0); | 454 | ppc_md.kexec_cpu_down(1, 0); |
417 | } | 455 | } |