[PATCH] MIPS: kexec mips64 XLR 732 support

wilbur.chan wilbur512 at gmail.com
Tue Dec 29 10:02:38 EST 2009


This patch works on mips64 xlr732 , which has 8 cores up to 32 threads.
derived from Maxim Syrchin's patch at
http://lists.infradead.org/pipermail/kexec/2008-June/001909.html

Notice:
(I)
 In my code,xlr kernel needs to call functions in bootloader when booting,
 so xlr bootloader is supposed to determin whether in first booting or second.
(II)
 As xlr kernel choosed CPU0 for special purpose when booting,I simply
bind kexec on CPU0.
(III)
 Becasue non-zero CPUs have different kernel entry with respect to
CPU0,they wait util CPU0 set flags at 0xa6000000.


Signed-off-by: wilbur <chen.yu10 at zte.com.cn>

--- machine_kexec.c 2007-08-05 00:11:13.000000000 +0800
+++ patch.machine_kexec.c 2009-12-29 14:31:32.000000000 +0800
@@ -13,12 +13,28 @@
 #include <asm/cacheflush.h>
 #include <asm/page.h>

+#ifdef CONFIG_RMI_PHOENIX
+#define KEXEC_FLAG_VAL  184790
+#define KEXEC_FLAG_POS   0xa6000000
+#define KEXEC_SECONDFUNC_POS   0xa6000004
+#define  V_CPUS                   31
+#endif
 extern const unsigned char relocate_new_kernel[];
+#ifdef CONFIG_RMI_PHOENIX
+extern const unsigned char kexec_smp_wait[];
+#endif
 extern const unsigned int relocate_new_kernel_size;

 extern unsigned long kexec_start_address;
 extern unsigned long kexec_indirection_page;

+#ifdef CONFIG_RMI_PHOENIX
+extern unsigned long kexec_fw_arg0;
+extern unsigned long kexec_fw_arg1;
+extern unsigned long kexec_fw_arg2;
+extern unsigned long kexec_fw_arg3;
+extern unsigned long fw_arg0,fw_arg1,fw_arg2,fw_arg3;
+#endif
 int
 machine_kexec_prepare(struct kimage *kimage)
 {
@@ -33,7 +49,70 @@
 void
 machine_shutdown(void)
 {
+ #ifdef CONFIG_RMI_PHOENIX
+ default_machine_kexec_shutdown();
+ #endif
 }
+#ifdef CONFIG_RMI_PHOENIX
+unsigned long relocated_kexec_smp_wait;
+atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
+int main_cpu = -1;
+static cpumask_t cpus_in_kexec = CPU_MASK_NONE;
+void machine_shutdown_secondary(void *ignore)
+{
+    int cpu = smp_processor_id();
+
+       if (!cpu_online(cpu))
+       return;
+
+ local_irq_disable();
+ uint64_t eimr=0;
+ write_64bit_cp0_eimr(eimr);
+
+
+
+ /*
+  * clear flags and secondary funtion before wait
+  */
+ *(unsigned long*)KEXEC_FLAG_POS =0;
+ *(unsigned long*)KEXEC_SECONDFUNC_POS =0;
+
+    cpu_set(cpu, cpus_in_kexec);
+
+   while(!atomic_read(&kexec_ready_to_reboot)) {
+        cpu_relax();
+    }
+
+ ((void (*)(void)) relocated_kexec_smp_wait)();
+    /* NOTREACHED */
+}
+static void machine_kexec_prepare_cpus(void)
+{
+
+    unsigned int msecs;
+    smp_call_function (machine_shutdown_secondary, NULL, 0, 0);
+    smp_wmb();
+    /*
+     * FIXME: Until we will have the way to stop other CPUSs reliabally,
+     * the crash CPU will send an IPI and wait for other CPUs to
+     * respond.
+     * Delay of at least 10 seconds.
+     */
+
+    msecs = 10000;
+    while ((cpus_weight(cpus_in_kexec) < V_CPUS) && (--msecs > 0)) {
+        cpu_relax();
+        mdelay(1);
+    }
+
+}
+void default_machine_kexec_shutdown()
+{
+ machine_kexec_prepare_cpus();
+}
+
+#endif

 void
 machine_crash_shutdown(struct pt_regs *regs)
@@ -50,7 +129,13 @@
  reboot_code_buffer =
    (unsigned long)page_address(image->control_code_page);

- kexec_start_address = image->start;
+ kexec_start_address = (unsigned long) phys_to_virt(image->start);
+ #ifdef CONFIG_RMI_PHOENIX
+  kexec_fw_arg0 = fw_arg0;
+  kexec_fw_arg1 = fw_arg1;
+  kexec_fw_arg2 = fw_arg2;
+  kexec_fw_arg3 = fw_arg3;
+ #endif
  kexec_indirection_page = phys_to_virt(image->head & PAGE_MASK);

  memcpy((void*)reboot_code_buffer, relocate_new_kernel,
@@ -75,10 +160,23 @@
   */
  local_irq_disable();

- flush_icache_range(reboot_code_buffer,
-      reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);

- printk("Will call new kernel at %08x\n", image->start);
+
+ #ifdef CONFIG_RMI_PHOENIX
+ pic_and_control(0xfffffbff);
+    /* All secondary cpus now may jump to kexec_wait cycle */
+    relocated_kexec_smp_wait = reboot_code_buffer +
+        (kexec_smp_wait - relocate_new_kernel);
+    smp_wmb();
+    atomic_set(&kexec_ready_to_reboot,1);
+ pic_irt_timer_maskall();
+ pic_irt_uart0_0_and(0x0);
+ pic_irt_uart0_1_and(0x0);
+ uart_int_and(0x0);
+  uint64_t eimr=0;
+ write_64bit_cp0_eimr(eimr);
+ #endif
+ printk("Will call new kernel at %08x\n", kexec_start_address);
  printk("Bye ...\n");
  flush_cache_all();
  ((void (*)(void))reboot_code_buffer)();

--- relocate_kernel.S 2007-08-05 00:11:13.000000000 +0800
+++ patch.relocate_kernel.S 2009-12-29 14:25:27.873991800 +0800
@@ -14,12 +14,21 @@
 #include <asm/stackframe.h>
 #include <asm/addrspace.h>

+#ifdef CONFIG_RMI_PHOENIX
+#define KEXEC_FLAG_POS   0xa6000000
+#define KEXEC_SECONDFUNC_POS   0xa6000004
+#endif
  .globl relocate_new_kernel
 relocate_new_kernel:

  PTR_L s0, kexec_indirection_page
  PTR_L s1, kexec_start_address
-
+#ifdef CONFIG_RMI_PHOENIX
+ PTR_L t0, kexec_fw_arg0
+ PTR_L t1, kexec_fw_arg1
+ PTR_L t2, kexec_fw_arg2
+ PTR_L t3, kexec_fw_arg3
+#endif
 process_entry:
  PTR_L s2, (s0)
  PTR_ADD s0, s0, SZREG
@@ -62,9 +71,39 @@
  b process_entry

 done:
+#ifdef CONFIG_RMI_PHOENIX
+ move      a0,  t0
+ move      a1,  t1
+ move      a2,  t2
+ move      a3,  t3
  /* jump to kexec_start_address */
- j s1
+ jr     s1
+#endif
+
+

+#ifdef CONFIG_RMI_PHOENIX
+ .globl kexec_smp_wait
+kexec_smp_wait:
+ /*
+  * wait util CPU0 set  flag at 0xa6000000, then jump to
secondary_function stored in 0xa6000004
+  *
+  */
+
+ /*
+  * FIXME
+  */
+20: li             s2,KEXEC_FLAG_POS
+ REG_L  s5, (s2)
+ beqz  s5, 20b
+
+ /*
+  * ok , we can jump to second kernel
+  */
+ li             s2,KEXEC_SECONDFUNC_POS
+ REG_L  s6, (s2)
+ jr            s6
+#endif
  .globl kexec_start_address
 kexec_start_address:
  .long 0x0
@@ -73,6 +112,25 @@
 kexec_indirection_page:
  .long 0x0

+#ifdef CONFIG_RMI_PHOENIX
+ .globl kexec_fw_arg0
+kexec_fw_arg0:
+ .long 0x0
+
+
+ .globl kexec_fw_arg1
+kexec_fw_arg1:
+ .long 0x0
+
+ .globl kexec_fw_arg2
+kexec_fw_arg2:
+ .long 0x0
+
+ .globl kexec_fw_arg3
+kexec_fw_arg3:
+ .long 0x0
+
+#endif
 relocate_new_kernel_end:

  .globl relocate_new_kernel_size



More information about the kexec mailing list