Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+156 -90
+21
arch/sh/include/asm/reboot.h
··· 1 + #ifndef __ASM_SH_REBOOT_H 2 + #define __ASM_SH_REBOOT_H 3 + 4 + #include <linux/kdebug.h> 5 + 6 + struct pt_regs; 7 + 8 + struct machine_ops { 9 + void (*restart)(char *cmd); 10 + void (*halt)(void); 11 + void (*power_off)(void); 12 + void (*shutdown)(void); 13 + void (*crash_shutdown)(struct pt_regs *); 14 + }; 15 + 16 + extern struct machine_ops machine_ops; 17 + 18 + /* arch/sh/kernel/machine_kexec.c */ 19 + void native_machine_crash_shutdown(struct pt_regs *regs); 20 + 21 + #endif /* __ASM_SH_REBOOT_H */
+1
arch/sh/include/asm/system.h
··· 143 143 void per_cpu_trap_init(void); 144 144 void default_idle(void); 145 145 void cpu_idle_wait(void); 146 + void stop_this_cpu(void *); 146 147 147 148 #ifdef CONFIG_SUPERH32 148 149 #define BUILD_TRAP_HANDLER(name) \
+12
arch/sh/include/asm/system_32.h
··· 2 2 #define __ASM_SH_SYSTEM_32_H 3 3 4 4 #include <linux/types.h> 5 + #include <asm/mmu.h> 5 6 6 7 #ifdef CONFIG_SH_DSP 7 8 ··· 216 215 217 216 int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, 218 217 struct mem_access *ma, int); 218 + 219 + static inline void trigger_address_error(void) 220 + { 221 + if (__in_29bit_mode()) 222 + __asm__ __volatile__ ( 223 + "ldc %0, sr\n\t" 224 + "mov.l @%1, %0" 225 + : 226 + : "r" (0x10000000), "r" (0x80000001) 227 + ); 228 + } 219 229 220 230 asmlinkage void do_address_error(struct pt_regs *regs, 221 231 unsigned long writeaccess,
+7
arch/sh/include/asm/system_64.h
··· 48 48 return (unsigned long long)(signed long long)(signed long)val; 49 49 } 50 50 51 + extern void phys_stext(void); 52 + 53 + static inline void trigger_address_error(void) 54 + { 55 + phys_stext(); 56 + } 57 + 51 58 #define SR_BL_LL 0x0000000010000000LL 52 59 53 60 static inline void set_bl_bit(void)
+2 -1
arch/sh/kernel/Makefile
··· 14 14 obj-y := debugtraps.o dma-nommu.o dumpstack.o \ 15 15 idle.o io.o io_generic.o irq.o \ 16 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 19 setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ 19 20 syscalls_$(BITS).o time.o topology.o traps.o \ 20 21 traps_$(BITS).o unwinder.o
+11 -3
arch/sh/kernel/idle.c
··· 20 20 #include <asm/system.h> 21 21 #include <asm/atomic.h> 22 22 23 - static int hlt_counter; 24 23 void (*pm_idle)(void) = NULL; 25 - void (*pm_power_off)(void); 26 - EXPORT_SYMBOL(pm_power_off); 24 + 25 + static int hlt_counter; 27 26 28 27 static int __init nohlt_setup(char *__unused) 29 28 { ··· 128 129 129 130 static void do_nothing(void *unused) 130 131 { 132 + } 133 + 134 + void stop_this_cpu(void *unused) 135 + { 136 + local_irq_disable(); 137 + cpu_clear(smp_processor_id(), cpu_online_map); 138 + 139 + for (;;) 140 + cpu_sleep(); 131 141 } 132 142 133 143 /*
+3 -5
arch/sh/kernel/machine_kexec.c
··· 22 22 #include <asm/io.h> 23 23 #include <asm/cacheflush.h> 24 24 #include <asm/sh_bios.h> 25 + #include <asm/reboot.h> 25 26 26 27 typedef void (*relocate_new_kernel_t)(unsigned long indirection_page, 27 28 unsigned long reboot_code_buffer, ··· 32 31 extern const unsigned int relocate_new_kernel_size; 33 32 extern void *vbr_base; 34 33 35 - void machine_shutdown(void) 34 + void native_machine_crash_shutdown(struct pt_regs *regs) 36 35 { 37 - } 38 - 39 - void machine_crash_shutdown(struct pt_regs *regs) 40 - { 36 + /* Nothing to do for UP, but definitely broken for SMP.. */ 41 37 } 42 38 43 39 /*
-48
arch/sh/kernel/process_32.c
··· 16 16 #include <linux/module.h> 17 17 #include <linux/mm.h> 18 18 #include <linux/elfcore.h> 19 - #include <linux/pm.h> 20 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 20 #include <linux/fs.h> 26 21 #include <linux/ftrace.h> 27 - #include <linux/preempt.h> 28 22 #include <linux/hw_breakpoint.h> 29 23 #include <asm/uaccess.h> 30 24 #include <asm/mmu_context.h> 31 - #include <asm/pgalloc.h> 32 25 #include <asm/system.h> 33 26 #include <asm/fpu.h> 34 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 29 void show_regs(struct pt_regs * regs) 78 30 {
+1 -24
arch/sh/kernel/process_64.c
··· 32 32 33 33 struct task_struct *last_task_used_math = NULL; 34 34 35 - void machine_restart(char * __unused) 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) 35 + void show_regs(struct pt_regs *regs) 59 36 { 60 37 unsigned long long ah, al, bh, bl, ch, cl; 61 38
+98
arch/sh/kernel/reboot.c
··· 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
-9
arch/sh/kernel/smp.c
··· 161 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 164 void smp_send_stop(void) 174 165 { 175 166 smp_call_function(stop_this_cpu, 0, 0);