Skip to content

Commit

Permalink
sh: machine_ops based reboot support.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Paul Mundt committed Jan 20, 2010
1 parent 2efa53b commit fbb82b0
Show file tree
Hide file tree
Showing 11 changed files with 156 additions and 90 deletions.
21 changes: 21 additions & 0 deletions arch/sh/include/asm/reboot.h
Original file line number Diff line number Diff line change
@@ -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 */
1 change: 1 addition & 0 deletions arch/sh/include/asm/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
12 changes: 12 additions & 0 deletions arch/sh/include/asm/system_32.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define __ASM_SH_SYSTEM_32_H

#include <linux/types.h>
#include <asm/mmu.h>

#ifdef CONFIG_SH_DSP

Expand Down Expand Up @@ -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);
Expand Down
7 changes: 7 additions & 0 deletions arch/sh/include/asm/system_64.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion arch/sh/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 11 additions & 3 deletions arch/sh/kernel/idle.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,9 @@
#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)
{
Expand Down Expand Up @@ -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
Expand Down
8 changes: 3 additions & 5 deletions arch/sh/kernel/machine_kexec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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.. */
}

/*
Expand Down
48 changes: 0 additions & 48 deletions arch/sh/kernel/process_32.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,63 +16,15 @@
#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)
{
Expand Down
25 changes: 1 addition & 24 deletions arch/sh/kernel/process_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,30 +32,7 @@

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;

Expand Down
98 changes: 98 additions & 0 deletions arch/sh/kernel/reboot.c
Original file line number Diff line number Diff line change
@@ -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
9 changes: 0 additions & 9 deletions arch/sh/kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit fbb82b0

Please sign in to comment.