Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux...
[pandora-kernel.git] / arch / powerpc / kernel / crash.c
index 6f4613d..8c066d6 100644 (file)
@@ -162,6 +162,32 @@ static void crash_kexec_prepare_cpus(int cpu)
        /* Leave the IPI callback set */
 }
 
+/* wait for all the CPUs to hit real mode but timeout if they don't come in */
+static void crash_kexec_wait_realmode(int cpu)
+{
+       unsigned int msecs;
+       int i;
+
+       msecs = 10000;
+       for (i=0; i < NR_CPUS && msecs > 0; i++) {
+               if (i == cpu)
+                       continue;
+
+               while (paca[i].kexec_state < KEXEC_STATE_REAL_MODE) {
+                       barrier();
+                       if (!cpu_possible(i)) {
+                               break;
+                       }
+                       if (!cpu_online(i)) {
+                               break;
+                       }
+                       msecs--;
+                       mdelay(1);
+               }
+       }
+       mb();
+}
+
 /*
  * This function will be called by secondary cpus or by kexec cpu
  * if soft-reset is activated to stop some CPUs.
@@ -347,10 +373,12 @@ int crash_shutdown_unregister(crash_shutdown_t handler)
 EXPORT_SYMBOL(crash_shutdown_unregister);
 
 static unsigned long crash_shutdown_buf[JMP_BUF_LEN];
+static int crash_shutdown_cpu = -1;
 
 static int handle_fault(struct pt_regs *regs)
 {
-       longjmp(crash_shutdown_buf, 1);
+       if (crash_shutdown_cpu == smp_processor_id())
+               longjmp(crash_shutdown_buf, 1);
        return 0;
 }
 
@@ -375,11 +403,14 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
        for_each_irq(i) {
                struct irq_desc *desc = irq_to_desc(i);
 
+               if (!desc || !desc->chip || !desc->chip->eoi)
+                       continue;
+
                if (desc->status & IRQ_INPROGRESS)
                        desc->chip->eoi(i);
 
                if (!(desc->status & IRQ_DISABLED))
-                       desc->chip->disable(i);
+                       desc->chip->shutdown(i);
        }
 
        /*
@@ -388,6 +419,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
         */
        old_handler = __debugger_fault_handler;
        __debugger_fault_handler = handle_fault;
+       crash_shutdown_cpu = smp_processor_id();
        for (i = 0; crash_shutdown_handles[i]; i++) {
                if (setjmp(crash_shutdown_buf) == 0) {
                        /*
@@ -401,6 +433,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
                        asm volatile("sync; isync");
                }
        }
+       crash_shutdown_cpu = -1;
        __debugger_fault_handler = old_handler;
 
        /*
@@ -412,6 +445,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
        crash_kexec_prepare_cpus(crashing_cpu);
        cpu_set(crashing_cpu, cpus_in_crash);
        crash_kexec_stop_spus();
+       crash_kexec_wait_realmode(crashing_cpu);
        if (ppc_md.kexec_cpu_down)
                ppc_md.kexec_cpu_down(1, 0);
 }