]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - arch/powerpc/kernel/crash.c
powerpc/kexec: Add ifdef CONFIG_PPC_STD_MMU_64 to PPC64 code
[karo-tx-linux.git] / arch / powerpc / kernel / crash.c
index eae401de3f769f08176838d9456a2e84c9ba786d..4de36b83331ace8b6586229342b5aa6ad04b5cf3 100644 (file)
@@ -48,7 +48,7 @@ int crashing_cpu = -1;
 static cpumask_t cpus_in_crash = CPU_MASK_NONE;
 cpumask_t cpus_in_sr = CPU_MASK_NONE;
 
-#define CRASH_HANDLER_MAX 1
+#define CRASH_HANDLER_MAX 2
 /* NULL terminated list of shutdown handles */
 static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1];
 static DEFINE_SPINLOCK(crash_handlers_lock);
@@ -162,6 +162,34 @@ 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 */
+#ifdef CONFIG_PPC_STD_MMU_64
+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();
+}
+#endif
+
 /*
  * This function will be called by secondary cpus or by kexec cpu
  * if soft-reset is activated to stop some CPUs.
@@ -347,10 +375,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 +405,14 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
        for_each_irq(i) {
                struct irq_desc *desc = irq_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 +421,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 +435,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 +447,9 @@ 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();
+#ifdef CONFIG_PPC_STD_MMU_64
+       crash_kexec_wait_realmode(crashing_cpu);
+#endif
        if (ppc_md.kexec_cpu_down)
                ppc_md.kexec_cpu_down(1, 0);
 }