diff options
Diffstat (limited to 'arch/powerpc/kernel/crash.c')
-rw-r--r-- | arch/powerpc/kernel/crash.c | 38 |
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 */ | ||
166 | static 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) | |||
347 | EXPORT_SYMBOL(crash_shutdown_unregister); | 373 | EXPORT_SYMBOL(crash_shutdown_unregister); |
348 | 374 | ||
349 | static unsigned long crash_shutdown_buf[JMP_BUF_LEN]; | 375 | static unsigned long crash_shutdown_buf[JMP_BUF_LEN]; |
376 | static int crash_shutdown_cpu = -1; | ||
350 | 377 | ||
351 | static int handle_fault(struct pt_regs *regs) | 378 | static 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 | } |