diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-01-20 02:42:52 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-01-20 02:42:52 -0500 |
commit | fbb82b03653cdb7fd1863b911e7540011259d2ce (patch) | |
tree | d5920f46068bb184a5322bc1505fb030adb6bfb6 /arch/sh/kernel | |
parent | 2efa53b269ec1e9289a108e1506f53f6f1de440b (diff) |
sh: machine_ops based reboot support.
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>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/sh/kernel/idle.c | 14 | ||||
-rw-r--r-- | arch/sh/kernel/machine_kexec.c | 8 | ||||
-rw-r--r-- | arch/sh/kernel/process_32.c | 48 | ||||
-rw-r--r-- | arch/sh/kernel/process_64.c | 25 | ||||
-rw-r--r-- | arch/sh/kernel/reboot.c | 98 | ||||
-rw-r--r-- | arch/sh/kernel/smp.c | 9 |
7 files changed, 115 insertions, 90 deletions
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index 56704a6d723a..02fd3ae8b0ee 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile | |||
@@ -14,7 +14,8 @@ CFLAGS_REMOVE_return_address.o = -pg | |||
14 | obj-y := debugtraps.o dma-nommu.o dumpstack.o \ | 14 | obj-y := debugtraps.o dma-nommu.o dumpstack.o \ |
15 | idle.o io.o io_generic.o irq.o \ | 15 | idle.o io.o io_generic.o irq.o \ |
16 | irq_$(BITS).o machvec.o nmi_debug.o process.o \ | 16 | irq_$(BITS).o machvec.o nmi_debug.o process.o \ |
17 | process_$(BITS).o ptrace_$(BITS).o return_address.o \ | 17 | process_$(BITS).o ptrace_$(BITS).o \ |
18 | reboot.o return_address.o \ | ||
18 | setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ | 19 | setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ |
19 | syscalls_$(BITS).o time.o topology.o traps.o \ | 20 | syscalls_$(BITS).o time.o topology.o traps.o \ |
20 | traps_$(BITS).o unwinder.o | 21 | traps_$(BITS).o unwinder.o |
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c index 6b3d706deac1..0fd7b41f0a22 100644 --- a/arch/sh/kernel/idle.c +++ b/arch/sh/kernel/idle.c | |||
@@ -20,10 +20,9 @@ | |||
20 | #include <asm/system.h> | 20 | #include <asm/system.h> |
21 | #include <asm/atomic.h> | 21 | #include <asm/atomic.h> |
22 | 22 | ||
23 | static int hlt_counter; | ||
24 | void (*pm_idle)(void) = NULL; | 23 | void (*pm_idle)(void) = NULL; |
25 | void (*pm_power_off)(void); | 24 | |
26 | EXPORT_SYMBOL(pm_power_off); | 25 | static int hlt_counter; |
27 | 26 | ||
28 | static int __init nohlt_setup(char *__unused) | 27 | static int __init nohlt_setup(char *__unused) |
29 | { | 28 | { |
@@ -131,6 +130,15 @@ static void do_nothing(void *unused) | |||
131 | { | 130 | { |
132 | } | 131 | } |
133 | 132 | ||
133 | void stop_this_cpu(void *unused) | ||
134 | { | ||
135 | local_irq_disable(); | ||
136 | cpu_clear(smp_processor_id(), cpu_online_map); | ||
137 | |||
138 | for (;;) | ||
139 | cpu_sleep(); | ||
140 | } | ||
141 | |||
134 | /* | 142 | /* |
135 | * cpu_idle_wait - Used to ensure that all the CPUs discard old value of | 143 | * cpu_idle_wait - Used to ensure that all the CPUs discard old value of |
136 | * pm_idle and update to new pm_idle value. Required while changing pm_idle | 144 | * pm_idle and update to new pm_idle value. Required while changing pm_idle |
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c index f52d8ed69e12..7672141c841b 100644 --- a/arch/sh/kernel/machine_kexec.c +++ b/arch/sh/kernel/machine_kexec.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <asm/io.h> | 22 | #include <asm/io.h> |
23 | #include <asm/cacheflush.h> | 23 | #include <asm/cacheflush.h> |
24 | #include <asm/sh_bios.h> | 24 | #include <asm/sh_bios.h> |
25 | #include <asm/reboot.h> | ||
25 | 26 | ||
26 | typedef void (*relocate_new_kernel_t)(unsigned long indirection_page, | 27 | typedef void (*relocate_new_kernel_t)(unsigned long indirection_page, |
27 | unsigned long reboot_code_buffer, | 28 | unsigned long reboot_code_buffer, |
@@ -31,12 +32,9 @@ extern const unsigned char relocate_new_kernel[]; | |||
31 | extern const unsigned int relocate_new_kernel_size; | 32 | extern const unsigned int relocate_new_kernel_size; |
32 | extern void *vbr_base; | 33 | extern void *vbr_base; |
33 | 34 | ||
34 | void machine_shutdown(void) | 35 | void native_machine_crash_shutdown(struct pt_regs *regs) |
35 | { | ||
36 | } | ||
37 | |||
38 | void machine_crash_shutdown(struct pt_regs *regs) | ||
39 | { | 36 | { |
37 | /* Nothing to do for UP, but definitely broken for SMP.. */ | ||
40 | } | 38 | } |
41 | 39 | ||
42 | /* | 40 | /* |
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 856010f9ebc9..b6f43f0ea743 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c | |||
@@ -16,63 +16,15 @@ | |||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | #include <linux/elfcore.h> | 18 | #include <linux/elfcore.h> |
19 | #include <linux/pm.h> | ||
20 | #include <linux/kallsyms.h> | 19 | #include <linux/kallsyms.h> |
21 | #include <linux/kexec.h> | ||
22 | #include <linux/kdebug.h> | ||
23 | #include <linux/tick.h> | ||
24 | #include <linux/reboot.h> | ||
25 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
26 | #include <linux/ftrace.h> | 21 | #include <linux/ftrace.h> |
27 | #include <linux/preempt.h> | ||
28 | #include <linux/hw_breakpoint.h> | 22 | #include <linux/hw_breakpoint.h> |
29 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
30 | #include <asm/mmu_context.h> | 24 | #include <asm/mmu_context.h> |
31 | #include <asm/pgalloc.h> | ||
32 | #include <asm/system.h> | 25 | #include <asm/system.h> |
33 | #include <asm/fpu.h> | 26 | #include <asm/fpu.h> |
34 | #include <asm/syscalls.h> | 27 | #include <asm/syscalls.h> |
35 | #include <asm/watchdog.h> | ||
36 | |||
37 | #ifdef CONFIG_32BIT | ||
38 | static void watchdog_trigger_immediate(void) | ||
39 | { | ||
40 | sh_wdt_write_cnt(0xFF); | ||
41 | sh_wdt_write_csr(0xC2); | ||
42 | } | ||
43 | |||
44 | void machine_restart(char * __unused) | ||
45 | { | ||
46 | local_irq_disable(); | ||
47 | |||
48 | /* Use watchdog timer to trigger reset */ | ||
49 | watchdog_trigger_immediate(); | ||
50 | |||
51 | while (1) | ||
52 | cpu_sleep(); | ||
53 | } | ||
54 | #else | ||
55 | void machine_restart(char * __unused) | ||
56 | { | ||
57 | /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */ | ||
58 | asm volatile("ldc %0, sr\n\t" | ||
59 | "mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001)); | ||
60 | } | ||
61 | #endif | ||
62 | |||
63 | void machine_halt(void) | ||
64 | { | ||
65 | local_irq_disable(); | ||
66 | |||
67 | while (1) | ||
68 | cpu_sleep(); | ||
69 | } | ||
70 | |||
71 | void machine_power_off(void) | ||
72 | { | ||
73 | if (pm_power_off) | ||
74 | pm_power_off(); | ||
75 | } | ||
76 | 28 | ||
77 | void show_regs(struct pt_regs * regs) | 29 | void show_regs(struct pt_regs * regs) |
78 | { | 30 | { |
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index c9554a70bd0e..6ae5987230f8 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c | |||
@@ -32,30 +32,7 @@ | |||
32 | 32 | ||
33 | struct task_struct *last_task_used_math = NULL; | 33 | struct task_struct *last_task_used_math = NULL; |
34 | 34 | ||
35 | void machine_restart(char * __unused) | 35 | void show_regs(struct pt_regs *regs) |
36 | { | ||
37 | extern void phys_stext(void); | ||
38 | |||
39 | phys_stext(); | ||
40 | } | ||
41 | |||
42 | void machine_halt(void) | ||
43 | { | ||
44 | for (;;); | ||
45 | } | ||
46 | |||
47 | void machine_power_off(void) | ||
48 | { | ||
49 | __asm__ __volatile__ ( | ||
50 | "sleep\n\t" | ||
51 | "synci\n\t" | ||
52 | "nop;nop;nop;nop\n\t" | ||
53 | ); | ||
54 | |||
55 | panic("Unexpected wakeup!\n"); | ||
56 | } | ||
57 | |||
58 | void show_regs(struct pt_regs * regs) | ||
59 | { | 36 | { |
60 | unsigned long long ah, al, bh, bl, ch, cl; | 37 | unsigned long long ah, al, bh, bl, ch, cl; |
61 | 38 | ||
diff --git a/arch/sh/kernel/reboot.c b/arch/sh/kernel/reboot.c new file mode 100644 index 000000000000..b1fca66bb92e --- /dev/null +++ b/arch/sh/kernel/reboot.c | |||
@@ -0,0 +1,98 @@ | |||
1 | #include <linux/pm.h> | ||
2 | #include <linux/kexec.h> | ||
3 | #include <linux/kernel.h> | ||
4 | #include <linux/reboot.h> | ||
5 | #include <linux/module.h> | ||
6 | #ifdef CONFIG_SUPERH32 | ||
7 | #include <asm/watchdog.h> | ||
8 | #endif | ||
9 | #include <asm/addrspace.h> | ||
10 | #include <asm/reboot.h> | ||
11 | #include <asm/system.h> | ||
12 | |||
13 | void (*pm_power_off)(void); | ||
14 | EXPORT_SYMBOL(pm_power_off); | ||
15 | |||
16 | #ifdef CONFIG_SUPERH32 | ||
17 | static void watchdog_trigger_immediate(void) | ||
18 | { | ||
19 | sh_wdt_write_cnt(0xFF); | ||
20 | sh_wdt_write_csr(0xC2); | ||
21 | } | ||
22 | #endif | ||
23 | |||
24 | static void native_machine_restart(char * __unused) | ||
25 | { | ||
26 | local_irq_disable(); | ||
27 | |||
28 | /* Address error with SR.BL=1 first. */ | ||
29 | trigger_address_error(); | ||
30 | |||
31 | #ifdef CONFIG_SUPERH32 | ||
32 | /* If that fails or is unsupported, go for the watchdog next. */ | ||
33 | watchdog_trigger_immediate(); | ||
34 | #endif | ||
35 | |||
36 | /* | ||
37 | * Give up and sleep. | ||
38 | */ | ||
39 | while (1) | ||
40 | cpu_sleep(); | ||
41 | } | ||
42 | |||
43 | static void native_machine_shutdown(void) | ||
44 | { | ||
45 | smp_send_stop(); | ||
46 | } | ||
47 | |||
48 | static void native_machine_power_off(void) | ||
49 | { | ||
50 | if (pm_power_off) | ||
51 | pm_power_off(); | ||
52 | } | ||
53 | |||
54 | static void native_machine_halt(void) | ||
55 | { | ||
56 | /* stop other cpus */ | ||
57 | machine_shutdown(); | ||
58 | |||
59 | /* stop this cpu */ | ||
60 | stop_this_cpu(NULL); | ||
61 | } | ||
62 | |||
63 | struct machine_ops machine_ops = { | ||
64 | .power_off = native_machine_power_off, | ||
65 | .shutdown = native_machine_shutdown, | ||
66 | .restart = native_machine_restart, | ||
67 | .halt = native_machine_halt, | ||
68 | #ifdef CONFIG_KEXEC | ||
69 | .crash_shutdown = native_machine_crash_shutdown, | ||
70 | #endif | ||
71 | }; | ||
72 | |||
73 | void machine_power_off(void) | ||
74 | { | ||
75 | machine_ops.power_off(); | ||
76 | } | ||
77 | |||
78 | void machine_shutdown(void) | ||
79 | { | ||
80 | machine_ops.shutdown(); | ||
81 | } | ||
82 | |||
83 | void machine_restart(char *cmd) | ||
84 | { | ||
85 | machine_ops.restart(cmd); | ||
86 | } | ||
87 | |||
88 | void machine_halt(void) | ||
89 | { | ||
90 | machine_ops.halt(); | ||
91 | } | ||
92 | |||
93 | #ifdef CONFIG_KEXEC | ||
94 | void machine_crash_shutdown(struct pt_regs *regs) | ||
95 | { | ||
96 | machine_ops.crash_shutdown(regs); | ||
97 | } | ||
98 | #endif | ||
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 983e0792d5f3..e124cf7008df 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c | |||
@@ -161,15 +161,6 @@ void smp_send_reschedule(int cpu) | |||
161 | plat_send_ipi(cpu, SMP_MSG_RESCHEDULE); | 161 | plat_send_ipi(cpu, SMP_MSG_RESCHEDULE); |
162 | } | 162 | } |
163 | 163 | ||
164 | static void stop_this_cpu(void *unused) | ||
165 | { | ||
166 | cpu_clear(smp_processor_id(), cpu_online_map); | ||
167 | local_irq_disable(); | ||
168 | |||
169 | for (;;) | ||
170 | cpu_relax(); | ||
171 | } | ||
172 | |||
173 | void smp_send_stop(void) | 164 | void smp_send_stop(void) |
174 | { | 165 | { |
175 | smp_call_function(stop_this_cpu, 0, 0); | 166 | smp_call_function(stop_this_cpu, 0, 0); |