]> git.openfabrics.org - ~emulex/infiniband.git/commitdiff
sh: machine_ops based reboot support.
authorPaul Mundt <lethal@linux-sh.org>
Wed, 20 Jan 2010 07:42:52 +0000 (16:42 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 20 Jan 2010 07:42:52 +0000 (16:42 +0900)
This provides a machine_ops-based reboot interface loosely cloned from
x86, and converts the native sh32 and sh64 cases over to it.

Necessary both for tying in SMP support and also enabling platforms like
SDK7786 to add support for their microcontroller-based power managers.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
arch/sh/include/asm/reboot.h [new file with mode: 0644]
arch/sh/include/asm/system.h
arch/sh/include/asm/system_32.h
arch/sh/include/asm/system_64.h
arch/sh/kernel/Makefile
arch/sh/kernel/idle.c
arch/sh/kernel/machine_kexec.c
arch/sh/kernel/process_32.c
arch/sh/kernel/process_64.c
arch/sh/kernel/reboot.c [new file with mode: 0644]
arch/sh/kernel/smp.c

diff --git a/arch/sh/include/asm/reboot.h b/arch/sh/include/asm/reboot.h
new file mode 100644 (file)
index 0000000..b3da0c6
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __ASM_SH_REBOOT_H
+#define __ASM_SH_REBOOT_H
+
+#include <linux/kdebug.h>
+
+struct pt_regs;
+
+struct machine_ops {
+       void (*restart)(char *cmd);
+       void (*halt)(void);
+       void (*power_off)(void);
+       void (*shutdown)(void);
+       void (*crash_shutdown)(struct pt_regs *);
+};
+
+extern struct machine_ops machine_ops;
+
+/* arch/sh/kernel/machine_kexec.c */
+void native_machine_crash_shutdown(struct pt_regs *regs);
+
+#endif /* __ASM_SH_REBOOT_H */
index 62e4fc1e4409d923910e460dc344033a579ae398..de2fc3963c12f54174ebda7a0d53d77cd4dbc564 100644 (file)
@@ -143,6 +143,7 @@ extern struct dentry *sh_debugfs_root;
 void per_cpu_trap_init(void);
 void default_idle(void);
 void cpu_idle_wait(void);
+void stop_this_cpu(void *);
 
 #ifdef CONFIG_SUPERH32
 #define BUILD_TRAP_HANDLER(name)                                       \
index 06814f5b59c7b95f81c9e6cab7fbea7b43f10364..34bd2bac9a5fce12f057465df064d6451e88ea80 100644 (file)
@@ -2,6 +2,7 @@
 #define __ASM_SH_SYSTEM_32_H
 
 #include <linux/types.h>
+#include <asm/mmu.h>
 
 #ifdef CONFIG_SH_DSP
 
@@ -216,6 +217,17 @@ static inline reg_size_t register_align(void *val)
 int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
                            struct mem_access *ma, int);
 
+static inline void trigger_address_error(void)
+{
+       if (__in_29bit_mode())
+               __asm__ __volatile__ (
+                       "ldc %0, sr\n\t"
+                       "mov.l @%1, %0"
+                       :
+                       : "r" (0x10000000), "r" (0x80000001)
+               );
+}
+
 asmlinkage void do_address_error(struct pt_regs *regs,
                                 unsigned long writeaccess,
                                 unsigned long address);
index ab1dd917ea87daa7ea7b82a061c8eb03f660c84a..604ba7802cc20be82004f8428592c6c418989904 100644 (file)
@@ -48,6 +48,13 @@ static inline reg_size_t register_align(void *val)
        return (unsigned long long)(signed long long)(signed long)val;
 }
 
+extern void phys_stext(void);
+
+static inline void trigger_address_error(void)
+{
+       phys_stext();
+}
+
 #define SR_BL_LL       0x0000000010000000LL
 
 static inline void set_bl_bit(void)
index 56704a6d723abebdef63a70638aff225db27b5f1..02fd3ae8b0eeb4fc7bcf4b651060d5bf9054a22f 100644 (file)
@@ -14,7 +14,8 @@ CFLAGS_REMOVE_return_address.o = -pg
 obj-y  := debugtraps.o dma-nommu.o dumpstack.o                         \
           idle.o io.o io_generic.o irq.o                               \
           irq_$(BITS).o machvec.o nmi_debug.o process.o                \
-          process_$(BITS).o ptrace_$(BITS).o return_address.o          \
+          process_$(BITS).o ptrace_$(BITS).o                           \
+          reboot.o return_address.o                                    \
           setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o            \
           syscalls_$(BITS).o time.o topology.o traps.o                 \
           traps_$(BITS).o unwinder.o
index 6b3d706deac10954b91bb1721639ce6e91044710..0fd7b41f0a2242c0e6a59e4e00048f7bd7f01c25 100644 (file)
 #include <asm/system.h>
 #include <asm/atomic.h>
 
-static int hlt_counter;
 void (*pm_idle)(void) = NULL;
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
+
+static int hlt_counter;
 
 static int __init nohlt_setup(char *__unused)
 {
@@ -131,6 +130,15 @@ static void do_nothing(void *unused)
 {
 }
 
+void stop_this_cpu(void *unused)
+{
+       local_irq_disable();
+       cpu_clear(smp_processor_id(), cpu_online_map);
+
+       for (;;)
+               cpu_sleep();
+}
+
 /*
  * cpu_idle_wait - Used to ensure that all the CPUs discard old value of
  * pm_idle and update to new pm_idle value. Required while changing pm_idle
index f52d8ed69e125b3e855c4f9043cf3f0c2e5155ce..7672141c841bfad756aa2457b7d3320577191eae 100644 (file)
@@ -22,6 +22,7 @@
 #include <asm/io.h>
 #include <asm/cacheflush.h>
 #include <asm/sh_bios.h>
+#include <asm/reboot.h>
 
 typedef void (*relocate_new_kernel_t)(unsigned long indirection_page,
                                      unsigned long reboot_code_buffer,
@@ -31,12 +32,9 @@ extern const unsigned char relocate_new_kernel[];
 extern const unsigned int relocate_new_kernel_size;
 extern void *vbr_base;
 
-void machine_shutdown(void)
-{
-}
-
-void machine_crash_shutdown(struct pt_regs *regs)
+void native_machine_crash_shutdown(struct pt_regs *regs)
 {
+       /* Nothing to do for UP, but definitely broken for SMP.. */
 }
 
 /*
index 856010f9ebc99f01186b3470e29752e9c53a6277..b6f43f0ea743576af3235c33db784312d829267c 100644 (file)
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <linux/elfcore.h>
-#include <linux/pm.h>
 #include <linux/kallsyms.h>
-#include <linux/kexec.h>
-#include <linux/kdebug.h>
-#include <linux/tick.h>
-#include <linux/reboot.h>
 #include <linux/fs.h>
 #include <linux/ftrace.h>
-#include <linux/preempt.h>
 #include <linux/hw_breakpoint.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
-#include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/fpu.h>
 #include <asm/syscalls.h>
-#include <asm/watchdog.h>
-
-#ifdef CONFIG_32BIT
-static void watchdog_trigger_immediate(void)
-{
-       sh_wdt_write_cnt(0xFF);
-       sh_wdt_write_csr(0xC2);
-}
-
-void machine_restart(char * __unused)
-{
-       local_irq_disable();
-
-       /* Use watchdog timer to trigger reset */
-       watchdog_trigger_immediate();
-
-       while (1)
-               cpu_sleep();
-}
-#else
-void machine_restart(char * __unused)
-{
-       /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
-       asm volatile("ldc %0, sr\n\t"
-                    "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
-}
-#endif
-
-void machine_halt(void)
-{
-       local_irq_disable();
-
-       while (1)
-               cpu_sleep();
-}
-
-void machine_power_off(void)
-{
-       if (pm_power_off)
-               pm_power_off();
-}
 
 void show_regs(struct pt_regs * regs)
 {
index c9554a70bd0e6305496d44b2bf132f3d226dbcc7..6ae5987230f8ab7f82813818fb5d875fa5feedfd 100644 (file)
 
 struct task_struct *last_task_used_math = NULL;
 
-void machine_restart(char * __unused)
-{
-       extern void phys_stext(void);
-
-       phys_stext();
-}
-
-void machine_halt(void)
-{
-       for (;;);
-}
-
-void machine_power_off(void)
-{
-       __asm__ __volatile__ (
-               "sleep\n\t"
-               "synci\n\t"
-               "nop;nop;nop;nop\n\t"
-       );
-
-       panic("Unexpected wakeup!\n");
-}
-
-void show_regs(struct pt_regs * regs)
+void show_regs(struct pt_regs *regs)
 {
        unsigned long long ah, al, bh, bl, ch, cl;
 
diff --git a/arch/sh/kernel/reboot.c b/arch/sh/kernel/reboot.c
new file mode 100644 (file)
index 0000000..b1fca66
--- /dev/null
@@ -0,0 +1,98 @@
+#include <linux/pm.h>
+#include <linux/kexec.h>
+#include <linux/kernel.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+#ifdef CONFIG_SUPERH32
+#include <asm/watchdog.h>
+#endif
+#include <asm/addrspace.h>
+#include <asm/reboot.h>
+#include <asm/system.h>
+
+void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
+
+#ifdef CONFIG_SUPERH32
+static void watchdog_trigger_immediate(void)
+{
+       sh_wdt_write_cnt(0xFF);
+       sh_wdt_write_csr(0xC2);
+}
+#endif
+
+static void native_machine_restart(char * __unused)
+{
+       local_irq_disable();
+
+       /* Address error with SR.BL=1 first. */
+       trigger_address_error();
+
+#ifdef CONFIG_SUPERH32
+       /* If that fails or is unsupported, go for the watchdog next. */
+       watchdog_trigger_immediate();
+#endif
+
+       /*
+        * Give up and sleep.
+        */
+       while (1)
+               cpu_sleep();
+}
+
+static void native_machine_shutdown(void)
+{
+       smp_send_stop();
+}
+
+static void native_machine_power_off(void)
+{
+       if (pm_power_off)
+               pm_power_off();
+}
+
+static void native_machine_halt(void)
+{
+       /* stop other cpus */
+       machine_shutdown();
+
+       /* stop this cpu */
+       stop_this_cpu(NULL);
+}
+
+struct machine_ops machine_ops = {
+       .power_off      = native_machine_power_off,
+       .shutdown       = native_machine_shutdown,
+       .restart        = native_machine_restart,
+       .halt           = native_machine_halt,
+#ifdef CONFIG_KEXEC
+       .crash_shutdown = native_machine_crash_shutdown,
+#endif
+};
+
+void machine_power_off(void)
+{
+       machine_ops.power_off();
+}
+
+void machine_shutdown(void)
+{
+       machine_ops.shutdown();
+}
+
+void machine_restart(char *cmd)
+{
+       machine_ops.restart(cmd);
+}
+
+void machine_halt(void)
+{
+       machine_ops.halt();
+}
+
+#ifdef CONFIG_KEXEC
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+       machine_ops.crash_shutdown(regs);
+}
+#endif
index 983e0792d5f31e8abea6fa7b99aeebcccc0c04ab..e124cf7008df46ed2e6de79f450901bd4161fbc5 100644 (file)
@@ -161,15 +161,6 @@ void smp_send_reschedule(int cpu)
        plat_send_ipi(cpu, SMP_MSG_RESCHEDULE);
 }
 
-static void stop_this_cpu(void *unused)
-{
-       cpu_clear(smp_processor_id(), cpu_online_map);
-       local_irq_disable();
-
-       for (;;)
-               cpu_relax();
-}
-
 void smp_send_stop(void)
 {
        smp_call_function(stop_this_cpu, 0, 0);