]> git.zerfleddert.de Git - ms2-kexec/blobdiff - machine_kexec.c
update offsets to new european GB kernel, set software booting from USB
[ms2-kexec] / machine_kexec.c
index 598ca61e7bca8496a853128a433dc7d1dfba0edf..9157d4c4ab21bb8bcc33429458dc4855ea17a8c2 100644 (file)
@@ -18,11 +18,15 @@ extern const unsigned int relocate_new_kernel_size;
 
 extern void setup_mm_for_reboot(char mode);
 
+extern void v7_flush_kern_cache_all(void);
+
 extern unsigned long kexec_start_address;
 extern unsigned long kexec_indirection_page;
 extern unsigned long kexec_mach_type;
 extern unsigned long kexec_boot_atags;
 
+static atomic_t waiting_for_crash_ipi;
+
 /*
  * Provide a dummy crash_notes definition while crash dump arrives to arm.
  * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
@@ -37,21 +41,53 @@ void machine_kexec_cleanup(struct kimage *image)
 {
 }
 
-void machine_shutdown(void)
+void machine_crash_nonpanic_core(void *unused)
 {
+       struct pt_regs regs;
+
+       crash_setup_regs(&regs, NULL);
+       printk(KERN_DEBUG "CPU %u will stop doing anything useful since another CPU has crashed\n",
+              smp_processor_id());
+       crash_save_cpu(&regs, smp_processor_id());
+       v7_flush_kern_cache_all();
+
+       atomic_dec(&waiting_for_crash_ipi);
+       while (1)
+               cpu_relax();
 }
 
 void machine_crash_shutdown(struct pt_regs *regs)
 {
+       unsigned long msecs;
+
+       local_irq_disable();
+
+       atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+       smp_call_function(machine_crash_nonpanic_core, NULL, false);
+       msecs = 1000; /* Wait at most a second for the other cpus to stop */
+       while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
+               mdelay(1);
+               msecs--;
+       }
+       if (atomic_read(&waiting_for_crash_ipi) > 0)
+               printk(KERN_WARNING "Non-crashing CPUs did not react to IPI\n");
+
+       crash_save_cpu(regs, smp_processor_id());
+
+       printk(KERN_INFO "Loading crashdump kernel...\n");
 }
 
+/*
+ * Function pointer to optional machine-specific reinitialization
+ */
+void (*kexec_reinit)(void);
+
 void machine_kexec(struct kimage *image)
 {
        unsigned long page_list;
        unsigned long reboot_code_buffer_phys;
        void *reboot_code_buffer;
 
-
        page_list = image->head & PAGE_MASK;
 
        /* we need both effective and real address here */
@@ -74,7 +110,20 @@ void machine_kexec(struct kimage *image)
                           (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
        printk(KERN_INFO "Bye!\n");
 
-       cpu_proc_fin();
+       if (kexec_reinit)
+               kexec_reinit();
+       local_irq_disable();
+       local_fiq_disable();
        setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/
+       v7_flush_kern_cache_all();
+#ifdef CONFIG_OUTER_CACHE
+       outer_flush_all();
+       outer_disable();
+#endif
+       cpu_proc_fin();
+#ifdef CONFIG_OUTER_CACHE
+       outer_inv_all();
+#endif
+       //v7_flush_kern_cache_all();
        cpu_reset(reboot_code_buffer_phys);
 }
Impressum, Datenschutz