aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/crash.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/crash.c')
-rw-r--r--arch/powerpc/kernel/crash.c38
1 files changed, 36 insertions, 2 deletions
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index 6f4613dd05ef..8c066d6a8e4b 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -162,6 +162,32 @@ 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 */
166static void crash_kexec_wait_realmode(int cpu)
167{
168 unsigned int msecs;
169 int i;
170
171 msecs = 10000;
172 for (i=0; i < NR_CPUS && msecs > 0; i++) {
173 if (i == cpu)
174 continue;
175
176 while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) {
177 barrier();
178 if (!cpu_possible(i)) {
179 break;
180 }
181 if (!cpu_online(i)) {
182 break;
183 }
184 msecs--;
185 mdelay(1);
186 }
187 }
188 mb();
189}
190
165/* 191/*
166 * This function will be called by secondary cpus or by kexec cpu 192 * This function will be called by secondary cpus or by kexec cpu
167 * if soft-reset is activated to stop some CPUs. 193 * if soft-reset is activated to stop some CPUs.
@@ -347,10 +373,12 @@ int crash_shutdown_unregister(crash_shutdown_t handler)
347EXPORT_SYMBOL(crash_shutdown_unregister); 373EXPORT_SYMBOL(crash_shutdown_unregister);
348 374
349static unsigned long crash_shutdown_buf[JMP_BUF_LEN]; 375static unsigned long crash_shutdown_buf[JMP_BUF_LEN];
376static int crash_shutdown_cpu = -1;
350 377
351static int handle_fault(struct pt_regs *regs) 378static int handle_fault(struct pt_regs *regs)
352{ 379{
353 longjmp(crash_shutdown_buf, 1); 380 if (crash_shutdown_cpu == smp_processor_id())
381 longjmp(crash_shutdown_buf, 1);
354 return 0; 382 return 0;
355} 383}
356 384
@@ -375,11 +403,14 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
375 for_each_irq(i) { 403 for_each_irq(i) {
376 struct irq_desc *desc = irq_to_desc(i); 404 struct irq_desc *desc = irq_to_desc(i);
377 405
406 if (!desc || !desc->chip || !desc->chip->eoi)
407 continue;
408
378 if (desc->status & IRQ_INPROGRESS) 409 if (desc->status & IRQ_INPROGRESS)
379 desc->chip->eoi(i); 410 desc->chip->eoi(i);
380 411
381 if (!(desc->status & IRQ_DISABLED)) 412 if (!(desc->status & IRQ_DISABLED))
382 desc->chip->disable(i); 413 desc->chip->shutdown(i);
383 } 414 }
384 415
385 /* 416 /*
@@ -388,6 +419,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
388 */ 419 */
389 old_handler = __debugger_fault_handler; 420 old_handler = __debugger_fault_handler;
390 __debugger_fault_handler = handle_fault; 421 __debugger_fault_handler = handle_fault;
422 crash_shutdown_cpu = smp_processor_id();
391 for (i = 0; crash_shutdown_handles[i]; i++) { 423 for (i = 0; crash_shutdown_handles[i]; i++) {
392 if (setjmp(crash_shutdown_buf) == 0) { 424 if (setjmp(crash_shutdown_buf) == 0) {
393 /* 425 /*
@@ -401,6 +433,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
401 asm volatile("sync; isync"); 433 asm volatile("sync; isync");
402 } 434 }
403 } 435 }
436 crash_shutdown_cpu = -1;
404 __debugger_fault_handler = old_handler; 437 __debugger_fault_handler = old_handler;
405 438
406 /* 439 /*
@@ -412,6 +445,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
412 crash_kexec_prepare_cpus(crashing_cpu); 445 crash_kexec_prepare_cpus(crashing_cpu);
413 cpu_set(crashing_cpu, cpus_in_crash); 446 cpu_set(crashing_cpu, cpus_in_crash);
414 crash_kexec_stop_spus(); 447 crash_kexec_stop_spus();
448 crash_kexec_wait_realmode(crashing_cpu);
415 if (ppc_md.kexec_cpu_down) 449 if (ppc_md.kexec_cpu_down)
416 ppc_md.kexec_cpu_down(1, 0); 450 ppc_md.kexec_cpu_down(1, 0);
417} 451}