diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-09 22:03:16 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-09 22:03:16 -0500 |
commit | 3a43aaa31790c36b69ebf8a6396f37fade86b531 (patch) | |
tree | 7c7f8da6219d546f2b44534cb7be1fb5591d6ac4 /arch/sh/kernel | |
parent | aed886ce777590eac87f7ce2897d9f8357754331 (diff) | |
parent | 6a5a0b9139b19dd1a107870269a35bc9cf18d2dc (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6: (137 commits)
sh: include empty zero page in romImage
sh: Make associative cache writes fatal on all SH-4A parts.
sh: Drop associative writes for SH-4 cache flushes.
sh: Partial revert of copy/clear_user_highpage() optimizations.
sh: Add default uImage rule for se7724, ap325rxa, and migor.
sh: allow runtime pm without suspend/resume callbacks
sh: mach-ecovec24: Remove un-defined settings for VPU
sh: mach-ecovec24: LCDC drive ability become high
sh: fix sh7724 VEU3F resource size
serial: sh-sci: Fix too early port disabling.
sh: pfc: pr_info() -> pr_debug() cleanups.
sh: pfc: Convert from ctrl_xxx() to __raw_xxx() I/O routines.
sh: Improve kfr2r09 serial port setup code
sh: Break out SuperH PFC code
sh: Move KEYSC header file
sh: convert /proc/cpu/aligmnent, /proc/cpu/kernel_alignment to seq_file
sh: Add CPG save/restore code for sh7724 R-standby
sh: Add SDHI power control support to Ecovec
mfd: Add power control platform data to SDHI driver
sh: mach-ecovec24: modify address map
...
Diffstat (limited to 'arch/sh/kernel')
49 files changed, 2429 insertions, 1188 deletions
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index a2d0a40f3848..0471a3eb25ed 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile | |||
@@ -9,8 +9,12 @@ ifdef CONFIG_FUNCTION_TRACER | |||
9 | CFLAGS_REMOVE_ftrace.o = -pg | 9 | CFLAGS_REMOVE_ftrace.o = -pg |
10 | endif | 10 | endif |
11 | 11 | ||
12 | obj-y := debugtraps.o dumpstack.o idle.o io.o io_generic.o irq.o \ | 12 | CFLAGS_REMOVE_return_address.o = -pg |
13 | machvec.o nmi_debug.o process_$(BITS).o ptrace_$(BITS).o \ | 13 | |
14 | obj-y := debugtraps.o dma-nommu.o dumpstack.o \ | ||
15 | idle.o io.o io_generic.o irq.o \ | ||
16 | irq_$(BITS).o machvec.o nmi_debug.o process_$(BITS).o \ | ||
17 | ptrace_$(BITS).o return_address.o \ | ||
14 | setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ | 18 | setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ |
15 | syscalls_$(BITS).o time.o topology.o traps.o \ | 19 | syscalls_$(BITS).o time.o topology.o traps.o \ |
16 | traps_$(BITS).o unwinder.o | 20 | traps_$(BITS).o unwinder.o |
@@ -28,13 +32,13 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | |||
28 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 32 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
29 | obj-$(CONFIG_IO_TRAPPED) += io_trapped.o | 33 | obj-$(CONFIG_IO_TRAPPED) += io_trapped.o |
30 | obj-$(CONFIG_KPROBES) += kprobes.o | 34 | obj-$(CONFIG_KPROBES) += kprobes.o |
31 | obj-$(CONFIG_GENERIC_GPIO) += gpio.o | ||
32 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 35 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
33 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o | 36 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o |
34 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 37 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
35 | obj-$(CONFIG_DUMP_CODE) += disassemble.o | 38 | obj-$(CONFIG_DUMP_CODE) += disassemble.o |
36 | obj-$(CONFIG_HIBERNATION) += swsusp.o | 39 | obj-$(CONFIG_HIBERNATION) += swsusp.o |
37 | obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o | 40 | obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o |
41 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o | ||
38 | 42 | ||
39 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o | 43 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o |
40 | 44 | ||
diff --git a/arch/sh/kernel/asm-offsets.c b/arch/sh/kernel/asm-offsets.c index d218e808294e..08a2be775b6c 100644 --- a/arch/sh/kernel/asm-offsets.c +++ b/arch/sh/kernel/asm-offsets.c | |||
@@ -34,5 +34,28 @@ int main(void) | |||
34 | DEFINE(PBE_NEXT, offsetof(struct pbe, next)); | 34 | DEFINE(PBE_NEXT, offsetof(struct pbe, next)); |
35 | DEFINE(SWSUSP_ARCH_REGS_SIZE, sizeof(struct swsusp_arch_regs)); | 35 | DEFINE(SWSUSP_ARCH_REGS_SIZE, sizeof(struct swsusp_arch_regs)); |
36 | #endif | 36 | #endif |
37 | |||
38 | DEFINE(SH_SLEEP_MODE, offsetof(struct sh_sleep_data, mode)); | ||
39 | DEFINE(SH_SLEEP_SF_PRE, offsetof(struct sh_sleep_data, sf_pre)); | ||
40 | DEFINE(SH_SLEEP_SF_POST, offsetof(struct sh_sleep_data, sf_post)); | ||
41 | DEFINE(SH_SLEEP_RESUME, offsetof(struct sh_sleep_data, resume)); | ||
42 | DEFINE(SH_SLEEP_VBR, offsetof(struct sh_sleep_data, vbr)); | ||
43 | DEFINE(SH_SLEEP_SPC, offsetof(struct sh_sleep_data, spc)); | ||
44 | DEFINE(SH_SLEEP_SR, offsetof(struct sh_sleep_data, sr)); | ||
45 | DEFINE(SH_SLEEP_SP, offsetof(struct sh_sleep_data, sp)); | ||
46 | DEFINE(SH_SLEEP_BASE_ADDR, offsetof(struct sh_sleep_data, addr)); | ||
47 | DEFINE(SH_SLEEP_BASE_DATA, offsetof(struct sh_sleep_data, data)); | ||
48 | DEFINE(SH_SLEEP_REG_STBCR, offsetof(struct sh_sleep_regs, stbcr)); | ||
49 | DEFINE(SH_SLEEP_REG_BAR, offsetof(struct sh_sleep_regs, bar)); | ||
50 | DEFINE(SH_SLEEP_REG_PTEH, offsetof(struct sh_sleep_regs, pteh)); | ||
51 | DEFINE(SH_SLEEP_REG_PTEL, offsetof(struct sh_sleep_regs, ptel)); | ||
52 | DEFINE(SH_SLEEP_REG_TTB, offsetof(struct sh_sleep_regs, ttb)); | ||
53 | DEFINE(SH_SLEEP_REG_TEA, offsetof(struct sh_sleep_regs, tea)); | ||
54 | DEFINE(SH_SLEEP_REG_MMUCR, offsetof(struct sh_sleep_regs, mmucr)); | ||
55 | DEFINE(SH_SLEEP_REG_PTEA, offsetof(struct sh_sleep_regs, ptea)); | ||
56 | DEFINE(SH_SLEEP_REG_PASCR, offsetof(struct sh_sleep_regs, pascr)); | ||
57 | DEFINE(SH_SLEEP_REG_IRMCR, offsetof(struct sh_sleep_regs, irmcr)); | ||
58 | DEFINE(SH_SLEEP_REG_CCR, offsetof(struct sh_sleep_regs, ccr)); | ||
59 | DEFINE(SH_SLEEP_REG_RAMCR, offsetof(struct sh_sleep_regs, ramcr)); | ||
37 | return 0; | 60 | return 0; |
38 | } | 61 | } |
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile index 3d6b9312dc47..d97c803719ec 100644 --- a/arch/sh/kernel/cpu/Makefile +++ b/arch/sh/kernel/cpu/Makefile | |||
@@ -15,7 +15,6 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/ | |||
15 | 15 | ||
16 | # Common interfaces. | 16 | # Common interfaces. |
17 | 17 | ||
18 | obj-$(CONFIG_UBC_WAKEUP) += ubc.o | ||
19 | obj-$(CONFIG_SH_ADC) += adc.o | 18 | obj-$(CONFIG_SH_ADC) += adc.o |
20 | obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o | 19 | obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o |
21 | 20 | ||
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index e932ebef4738..89b4b76c0d76 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c | |||
@@ -75,16 +75,11 @@ static void __init expmask_init(void) | |||
75 | /* | 75 | /* |
76 | * Future proofing. | 76 | * Future proofing. |
77 | * | 77 | * |
78 | * Disable support for slottable sleep instruction | 78 | * Disable support for slottable sleep instruction, non-nop |
79 | * and non-nop instructions in the rte delay slot. | 79 | * instructions in the rte delay slot, and associative writes to |
80 | * the memory-mapped cache array. | ||
80 | */ | 81 | */ |
81 | expmask &= ~(EXPMASK_RTEDS | EXPMASK_BRDSSLP); | 82 | expmask &= ~(EXPMASK_RTEDS | EXPMASK_BRDSSLP | EXPMASK_MMCAW); |
82 | |||
83 | /* | ||
84 | * Enable associative writes to the memory-mapped cache array | ||
85 | * until the cache flush ops have been rewritten. | ||
86 | */ | ||
87 | expmask |= EXPMASK_MMCAW; | ||
88 | 83 | ||
89 | __raw_writel(expmask, EXPMASK); | 84 | __raw_writel(expmask, EXPMASK); |
90 | ctrl_barrier(); | 85 | ctrl_barrier(); |
@@ -311,12 +306,12 @@ asmlinkage void __init sh_cpu_init(void) | |||
311 | if (fpu_disabled) { | 306 | if (fpu_disabled) { |
312 | printk("FPU Disabled\n"); | 307 | printk("FPU Disabled\n"); |
313 | current_cpu_data.flags &= ~CPU_HAS_FPU; | 308 | current_cpu_data.flags &= ~CPU_HAS_FPU; |
314 | disable_fpu(); | ||
315 | } | 309 | } |
316 | 310 | ||
317 | /* FPU initialization */ | 311 | /* FPU initialization */ |
312 | disable_fpu(); | ||
318 | if ((current_cpu_data.flags & CPU_HAS_FPU)) { | 313 | if ((current_cpu_data.flags & CPU_HAS_FPU)) { |
319 | clear_thread_flag(TIF_USEDFPU); | 314 | current_thread_info()->status &= ~TS_USEDFPU; |
320 | clear_used_math(); | 315 | clear_used_math(); |
321 | } | 316 | } |
322 | 317 | ||
@@ -338,17 +333,6 @@ asmlinkage void __init sh_cpu_init(void) | |||
338 | } | 333 | } |
339 | #endif | 334 | #endif |
340 | 335 | ||
341 | /* | ||
342 | * Some brain-damaged loaders decided it would be a good idea to put | ||
343 | * the UBC to sleep. This causes some issues when it comes to things | ||
344 | * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So .. | ||
345 | * we wake it up and hope that all is well. | ||
346 | */ | ||
347 | #ifdef CONFIG_SUPERH32 | ||
348 | if (raw_smp_processor_id() == 0) | ||
349 | ubc_wakeup(); | ||
350 | #endif | ||
351 | |||
352 | speculative_execution_init(); | 336 | speculative_execution_init(); |
353 | expmask_init(); | 337 | expmask_init(); |
354 | } | 338 | } |
diff --git a/arch/sh/kernel/cpu/sh2a/fpu.c b/arch/sh/kernel/cpu/sh2a/fpu.c index 6df2fb98eb30..d395ce5740e7 100644 --- a/arch/sh/kernel/cpu/sh2a/fpu.c +++ b/arch/sh/kernel/cpu/sh2a/fpu.c | |||
@@ -25,14 +25,12 @@ | |||
25 | 25 | ||
26 | /* | 26 | /* |
27 | * Save FPU registers onto task structure. | 27 | * Save FPU registers onto task structure. |
28 | * Assume called with FPU enabled (SR.FD=0). | ||
29 | */ | 28 | */ |
30 | void | 29 | void |
31 | save_fpu(struct task_struct *tsk, struct pt_regs *regs) | 30 | save_fpu(struct task_struct *tsk) |
32 | { | 31 | { |
33 | unsigned long dummy; | 32 | unsigned long dummy; |
34 | 33 | ||
35 | clear_tsk_thread_flag(tsk, TIF_USEDFPU); | ||
36 | enable_fpu(); | 34 | enable_fpu(); |
37 | asm volatile("sts.l fpul, @-%0\n\t" | 35 | asm volatile("sts.l fpul, @-%0\n\t" |
38 | "sts.l fpscr, @-%0\n\t" | 36 | "sts.l fpscr, @-%0\n\t" |
@@ -60,7 +58,6 @@ save_fpu(struct task_struct *tsk, struct pt_regs *regs) | |||
60 | : "memory"); | 58 | : "memory"); |
61 | 59 | ||
62 | disable_fpu(); | 60 | disable_fpu(); |
63 | release_fpu(regs); | ||
64 | } | 61 | } |
65 | 62 | ||
66 | static void | 63 | static void |
@@ -598,31 +595,31 @@ BUILD_TRAP_HANDLER(fpu_error) | |||
598 | struct task_struct *tsk = current; | 595 | struct task_struct *tsk = current; |
599 | TRAP_HANDLER_DECL; | 596 | TRAP_HANDLER_DECL; |
600 | 597 | ||
601 | save_fpu(tsk, regs); | 598 | __unlazy_fpu(tsk, regs); |
602 | if (ieee_fpe_handler(regs)) { | 599 | if (ieee_fpe_handler(regs)) { |
603 | tsk->thread.fpu.hard.fpscr &= | 600 | tsk->thread.fpu.hard.fpscr &= |
604 | ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); | 601 | ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); |
605 | grab_fpu(regs); | 602 | grab_fpu(regs); |
606 | restore_fpu(tsk); | 603 | restore_fpu(tsk); |
607 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 604 | task_thread_info(tsk)->status |= TS_USEDFPU; |
608 | return; | 605 | return; |
609 | } | 606 | } |
610 | 607 | ||
611 | force_sig(SIGFPE, tsk); | 608 | force_sig(SIGFPE, tsk); |
612 | } | 609 | } |
613 | 610 | ||
614 | BUILD_TRAP_HANDLER(fpu_state_restore) | 611 | void fpu_state_restore(struct pt_regs *regs) |
615 | { | 612 | { |
616 | struct task_struct *tsk = current; | 613 | struct task_struct *tsk = current; |
617 | TRAP_HANDLER_DECL; | ||
618 | 614 | ||
619 | grab_fpu(regs); | 615 | grab_fpu(regs); |
620 | if (!user_mode(regs)) { | 616 | if (unlikely(!user_mode(regs))) { |
621 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); | 617 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); |
618 | BUG(); | ||
622 | return; | 619 | return; |
623 | } | 620 | } |
624 | 621 | ||
625 | if (used_math()) { | 622 | if (likely(used_math())) { |
626 | /* Using the FPU again. */ | 623 | /* Using the FPU again. */ |
627 | restore_fpu(tsk); | 624 | restore_fpu(tsk); |
628 | } else { | 625 | } else { |
@@ -630,5 +627,13 @@ BUILD_TRAP_HANDLER(fpu_state_restore) | |||
630 | fpu_init(); | 627 | fpu_init(); |
631 | set_used_math(); | 628 | set_used_math(); |
632 | } | 629 | } |
633 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 630 | task_thread_info(tsk)->status |= TS_USEDFPU; |
631 | tsk->fpu_counter++; | ||
632 | } | ||
633 | |||
634 | BUILD_TRAP_HANDLER(fpu_state_restore) | ||
635 | { | ||
636 | TRAP_HANDLER_DECL; | ||
637 | |||
638 | fpu_state_restore(regs); | ||
634 | } | 639 | } |
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index bb407ef0b91e..3f7e2a22c7c2 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S | |||
@@ -297,41 +297,8 @@ ENTRY(vbr_base) | |||
297 | ! | 297 | ! |
298 | .balign 256,0,256 | 298 | .balign 256,0,256 |
299 | general_exception: | 299 | general_exception: |
300 | #ifndef CONFIG_CPU_SUBTYPE_SHX3 | ||
301 | bra handle_exception | 300 | bra handle_exception |
302 | sts pr, k3 ! save original pr value in k3 | 301 | sts pr, k3 ! save original pr value in k3 |
303 | #else | ||
304 | mov.l 1f, k4 | ||
305 | mov.l @k4, k4 | ||
306 | |||
307 | ! Is EXPEVT larger than 0x800? | ||
308 | mov #0x8, k0 | ||
309 | shll8 k0 | ||
310 | cmp/hs k0, k4 | ||
311 | bf 0f | ||
312 | |||
313 | ! then add 0x580 (k2 is 0xd80 or 0xda0) | ||
314 | mov #0x58, k0 | ||
315 | shll2 k0 | ||
316 | shll2 k0 | ||
317 | add k0, k4 | ||
318 | 0: | ||
319 | ! Setup stack and save DSP context (k0 contains original r15 on return) | ||
320 | bsr prepare_stack | ||
321 | nop | ||
322 | |||
323 | ! Save registers / Switch to bank 0 | ||
324 | mov k4, k2 ! keep vector in k2 | ||
325 | mov.l 1f, k4 ! SR bits to clear in k4 | ||
326 | bsr save_regs ! needs original pr value in k3 | ||
327 | nop | ||
328 | |||
329 | bra handle_exception_special | ||
330 | nop | ||
331 | |||
332 | .align 2 | ||
333 | 1: .long EXPEVT | ||
334 | #endif | ||
335 | 302 | ||
336 | ! prepare_stack() | 303 | ! prepare_stack() |
337 | ! - roll back gRB | 304 | ! - roll back gRB |
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile index 203b18347b83..3a1dbc709831 100644 --- a/arch/sh/kernel/cpu/sh4/Makefile +++ b/arch/sh/kernel/cpu/sh4/Makefile | |||
@@ -9,6 +9,11 @@ obj-$(CONFIG_HIBERNATION) += $(addprefix ../sh3/, swsusp.o) | |||
9 | obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o | 9 | obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o |
10 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o | 10 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o |
11 | 11 | ||
12 | # Perf events | ||
13 | perf-$(CONFIG_CPU_SUBTYPE_SH7750) := perf_event.o | ||
14 | perf-$(CONFIG_CPU_SUBTYPE_SH7750S) := perf_event.o | ||
15 | perf-$(CONFIG_CPU_SUBTYPE_SH7091) := perf_event.o | ||
16 | |||
12 | # CPU subtype setup | 17 | # CPU subtype setup |
13 | obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o | 18 | obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o |
14 | obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o | 19 | obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o |
@@ -27,4 +32,5 @@ endif | |||
27 | # Additional clocks by subtype | 32 | # Additional clocks by subtype |
28 | clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o | 33 | clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o |
29 | 34 | ||
30 | obj-y += $(clock-y) | 35 | obj-y += $(clock-y) |
36 | obj-$(CONFIG_PERF_EVENTS) += $(perf-y) | ||
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c index e3ea5411da6d..e97857aec8a0 100644 --- a/arch/sh/kernel/cpu/sh4/fpu.c +++ b/arch/sh/kernel/cpu/sh4/fpu.c | |||
@@ -41,13 +41,11 @@ static unsigned int fpu_exception_flags; | |||
41 | 41 | ||
42 | /* | 42 | /* |
43 | * Save FPU registers onto task structure. | 43 | * Save FPU registers onto task structure. |
44 | * Assume called with FPU enabled (SR.FD=0). | ||
45 | */ | 44 | */ |
46 | void save_fpu(struct task_struct *tsk, struct pt_regs *regs) | 45 | void save_fpu(struct task_struct *tsk) |
47 | { | 46 | { |
48 | unsigned long dummy; | 47 | unsigned long dummy; |
49 | 48 | ||
50 | clear_tsk_thread_flag(tsk, TIF_USEDFPU); | ||
51 | enable_fpu(); | 49 | enable_fpu(); |
52 | asm volatile ("sts.l fpul, @-%0\n\t" | 50 | asm volatile ("sts.l fpul, @-%0\n\t" |
53 | "sts.l fpscr, @-%0\n\t" | 51 | "sts.l fpscr, @-%0\n\t" |
@@ -92,7 +90,6 @@ void save_fpu(struct task_struct *tsk, struct pt_regs *regs) | |||
92 | :"memory"); | 90 | :"memory"); |
93 | 91 | ||
94 | disable_fpu(); | 92 | disable_fpu(); |
95 | release_fpu(regs); | ||
96 | } | 93 | } |
97 | 94 | ||
98 | static void restore_fpu(struct task_struct *tsk) | 95 | static void restore_fpu(struct task_struct *tsk) |
@@ -285,7 +282,6 @@ static int ieee_fpe_handler(struct pt_regs *regs) | |||
285 | /* fcnvsd */ | 282 | /* fcnvsd */ |
286 | struct task_struct *tsk = current; | 283 | struct task_struct *tsk = current; |
287 | 284 | ||
288 | save_fpu(tsk, regs); | ||
289 | if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR)) | 285 | if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR)) |
290 | /* FPU error */ | 286 | /* FPU error */ |
291 | denormal_to_double(&tsk->thread.fpu.hard, | 287 | denormal_to_double(&tsk->thread.fpu.hard, |
@@ -462,7 +458,7 @@ BUILD_TRAP_HANDLER(fpu_error) | |||
462 | struct task_struct *tsk = current; | 458 | struct task_struct *tsk = current; |
463 | TRAP_HANDLER_DECL; | 459 | TRAP_HANDLER_DECL; |
464 | 460 | ||
465 | save_fpu(tsk, regs); | 461 | __unlazy_fpu(tsk, regs); |
466 | fpu_exception_flags = 0; | 462 | fpu_exception_flags = 0; |
467 | if (ieee_fpe_handler(regs)) { | 463 | if (ieee_fpe_handler(regs)) { |
468 | tsk->thread.fpu.hard.fpscr &= | 464 | tsk->thread.fpu.hard.fpscr &= |
@@ -473,7 +469,7 @@ BUILD_TRAP_HANDLER(fpu_error) | |||
473 | tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10); | 469 | tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10); |
474 | grab_fpu(regs); | 470 | grab_fpu(regs); |
475 | restore_fpu(tsk); | 471 | restore_fpu(tsk); |
476 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 472 | task_thread_info(tsk)->status |= TS_USEDFPU; |
477 | if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) & | 473 | if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) & |
478 | (fpu_exception_flags >> 2)) == 0) { | 474 | (fpu_exception_flags >> 2)) == 0) { |
479 | return; | 475 | return; |
@@ -483,18 +479,18 @@ BUILD_TRAP_HANDLER(fpu_error) | |||
483 | force_sig(SIGFPE, tsk); | 479 | force_sig(SIGFPE, tsk); |
484 | } | 480 | } |
485 | 481 | ||
486 | BUILD_TRAP_HANDLER(fpu_state_restore) | 482 | void fpu_state_restore(struct pt_regs *regs) |
487 | { | 483 | { |
488 | struct task_struct *tsk = current; | 484 | struct task_struct *tsk = current; |
489 | TRAP_HANDLER_DECL; | ||
490 | 485 | ||
491 | grab_fpu(regs); | 486 | grab_fpu(regs); |
492 | if (!user_mode(regs)) { | 487 | if (unlikely(!user_mode(regs))) { |
493 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); | 488 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); |
489 | BUG(); | ||
494 | return; | 490 | return; |
495 | } | 491 | } |
496 | 492 | ||
497 | if (used_math()) { | 493 | if (likely(used_math())) { |
498 | /* Using the FPU again. */ | 494 | /* Using the FPU again. */ |
499 | restore_fpu(tsk); | 495 | restore_fpu(tsk); |
500 | } else { | 496 | } else { |
@@ -502,5 +498,13 @@ BUILD_TRAP_HANDLER(fpu_state_restore) | |||
502 | fpu_init(); | 498 | fpu_init(); |
503 | set_used_math(); | 499 | set_used_math(); |
504 | } | 500 | } |
505 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 501 | task_thread_info(tsk)->status |= TS_USEDFPU; |
502 | tsk->fpu_counter++; | ||
503 | } | ||
504 | |||
505 | BUILD_TRAP_HANDLER(fpu_state_restore) | ||
506 | { | ||
507 | TRAP_HANDLER_DECL; | ||
508 | |||
509 | fpu_state_restore(regs); | ||
506 | } | 510 | } |
diff --git a/arch/sh/kernel/cpu/sh4/perf_event.c b/arch/sh/kernel/cpu/sh4/perf_event.c new file mode 100644 index 000000000000..7f9ecc9c2d02 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4/perf_event.c | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * Performance events support for SH7750-style performance counters | ||
3 | * | ||
4 | * Copyright (C) 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/irq.h> | ||
14 | #include <linux/perf_event.h> | ||
15 | #include <asm/processor.h> | ||
16 | |||
17 | #define PM_CR_BASE 0xff000084 /* 16-bit */ | ||
18 | #define PM_CTR_BASE 0xff100004 /* 32-bit */ | ||
19 | |||
20 | #define PMCR(n) (PM_CR_BASE + ((n) * 0x04)) | ||
21 | #define PMCTRH(n) (PM_CTR_BASE + 0x00 + ((n) * 0x08)) | ||
22 | #define PMCTRL(n) (PM_CTR_BASE + 0x04 + ((n) * 0x08)) | ||
23 | |||
24 | #define PMCR_PMM_MASK 0x0000003f | ||
25 | |||
26 | #define PMCR_CLKF 0x00000100 | ||
27 | #define PMCR_PMCLR 0x00002000 | ||
28 | #define PMCR_PMST 0x00004000 | ||
29 | #define PMCR_PMEN 0x00008000 | ||
30 | |||
31 | static struct sh_pmu sh7750_pmu; | ||
32 | |||
33 | /* | ||
34 | * There are a number of events supported by each counter (33 in total). | ||
35 | * Since we have 2 counters, each counter will take the event code as it | ||
36 | * corresponds to the PMCR PMM setting. Each counter can be configured | ||
37 | * independently. | ||
38 | * | ||
39 | * Event Code Description | ||
40 | * ---------- ----------- | ||
41 | * | ||
42 | * 0x01 Operand read access | ||
43 | * 0x02 Operand write access | ||
44 | * 0x03 UTLB miss | ||
45 | * 0x04 Operand cache read miss | ||
46 | * 0x05 Operand cache write miss | ||
47 | * 0x06 Instruction fetch (w/ cache) | ||
48 | * 0x07 Instruction TLB miss | ||
49 | * 0x08 Instruction cache miss | ||
50 | * 0x09 All operand accesses | ||
51 | * 0x0a All instruction accesses | ||
52 | * 0x0b OC RAM operand access | ||
53 | * 0x0d On-chip I/O space access | ||
54 | * 0x0e Operand access (r/w) | ||
55 | * 0x0f Operand cache miss (r/w) | ||
56 | * 0x10 Branch instruction | ||
57 | * 0x11 Branch taken | ||
58 | * 0x12 BSR/BSRF/JSR | ||
59 | * 0x13 Instruction execution | ||
60 | * 0x14 Instruction execution in parallel | ||
61 | * 0x15 FPU Instruction execution | ||
62 | * 0x16 Interrupt | ||
63 | * 0x17 NMI | ||
64 | * 0x18 trapa instruction execution | ||
65 | * 0x19 UBCA match | ||
66 | * 0x1a UBCB match | ||
67 | * 0x21 Instruction cache fill | ||
68 | * 0x22 Operand cache fill | ||
69 | * 0x23 Elapsed time | ||
70 | * 0x24 Pipeline freeze by I-cache miss | ||
71 | * 0x25 Pipeline freeze by D-cache miss | ||
72 | * 0x27 Pipeline freeze by branch instruction | ||
73 | * 0x28 Pipeline freeze by CPU register | ||
74 | * 0x29 Pipeline freeze by FPU | ||
75 | */ | ||
76 | |||
77 | static const int sh7750_general_events[] = { | ||
78 | [PERF_COUNT_HW_CPU_CYCLES] = 0x0023, | ||
79 | [PERF_COUNT_HW_INSTRUCTIONS] = 0x000a, | ||
80 | [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0006, /* I-cache */ | ||
81 | [PERF_COUNT_HW_CACHE_MISSES] = 0x0008, /* I-cache */ | ||
82 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0010, | ||
83 | [PERF_COUNT_HW_BRANCH_MISSES] = -1, | ||
84 | [PERF_COUNT_HW_BUS_CYCLES] = -1, | ||
85 | }; | ||
86 | |||
87 | #define C(x) PERF_COUNT_HW_CACHE_##x | ||
88 | |||
89 | static const int sh7750_cache_events | ||
90 | [PERF_COUNT_HW_CACHE_MAX] | ||
91 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
92 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = | ||
93 | { | ||
94 | [ C(L1D) ] = { | ||
95 | [ C(OP_READ) ] = { | ||
96 | [ C(RESULT_ACCESS) ] = 0x0001, | ||
97 | [ C(RESULT_MISS) ] = 0x0004, | ||
98 | }, | ||
99 | [ C(OP_WRITE) ] = { | ||
100 | [ C(RESULT_ACCESS) ] = 0x0002, | ||
101 | [ C(RESULT_MISS) ] = 0x0005, | ||
102 | }, | ||
103 | [ C(OP_PREFETCH) ] = { | ||
104 | [ C(RESULT_ACCESS) ] = 0, | ||
105 | [ C(RESULT_MISS) ] = 0, | ||
106 | }, | ||
107 | }, | ||
108 | |||
109 | [ C(L1I) ] = { | ||
110 | [ C(OP_READ) ] = { | ||
111 | [ C(RESULT_ACCESS) ] = 0x0006, | ||
112 | [ C(RESULT_MISS) ] = 0x0008, | ||
113 | }, | ||
114 | [ C(OP_WRITE) ] = { | ||
115 | [ C(RESULT_ACCESS) ] = -1, | ||
116 | [ C(RESULT_MISS) ] = -1, | ||
117 | }, | ||
118 | [ C(OP_PREFETCH) ] = { | ||
119 | [ C(RESULT_ACCESS) ] = 0, | ||
120 | [ C(RESULT_MISS) ] = 0, | ||
121 | }, | ||
122 | }, | ||
123 | |||
124 | [ C(LL) ] = { | ||
125 | [ C(OP_READ) ] = { | ||
126 | [ C(RESULT_ACCESS) ] = 0, | ||
127 | [ C(RESULT_MISS) ] = 0, | ||
128 | }, | ||
129 | [ C(OP_WRITE) ] = { | ||
130 | [ C(RESULT_ACCESS) ] = 0, | ||
131 | [ C(RESULT_MISS) ] = 0, | ||
132 | }, | ||
133 | [ C(OP_PREFETCH) ] = { | ||
134 | [ C(RESULT_ACCESS) ] = 0, | ||
135 | [ C(RESULT_MISS) ] = 0, | ||
136 | }, | ||
137 | }, | ||
138 | |||
139 | [ C(DTLB) ] = { | ||
140 | [ C(OP_READ) ] = { | ||
141 | [ C(RESULT_ACCESS) ] = 0, | ||
142 | [ C(RESULT_MISS) ] = 0x0003, | ||
143 | }, | ||
144 | [ C(OP_WRITE) ] = { | ||
145 | [ C(RESULT_ACCESS) ] = 0, | ||
146 | [ C(RESULT_MISS) ] = 0, | ||
147 | }, | ||
148 | [ C(OP_PREFETCH) ] = { | ||
149 | [ C(RESULT_ACCESS) ] = 0, | ||
150 | [ C(RESULT_MISS) ] = 0, | ||
151 | }, | ||
152 | }, | ||
153 | |||
154 | [ C(ITLB) ] = { | ||
155 | [ C(OP_READ) ] = { | ||
156 | [ C(RESULT_ACCESS) ] = 0, | ||
157 | [ C(RESULT_MISS) ] = 0x0007, | ||
158 | }, | ||
159 | [ C(OP_WRITE) ] = { | ||
160 | [ C(RESULT_ACCESS) ] = -1, | ||
161 | [ C(RESULT_MISS) ] = -1, | ||
162 | }, | ||
163 | [ C(OP_PREFETCH) ] = { | ||
164 | [ C(RESULT_ACCESS) ] = -1, | ||
165 | [ C(RESULT_MISS) ] = -1, | ||
166 | }, | ||
167 | }, | ||
168 | |||
169 | [ C(BPU) ] = { | ||
170 | [ C(OP_READ) ] = { | ||
171 | [ C(RESULT_ACCESS) ] = -1, | ||
172 | [ C(RESULT_MISS) ] = -1, | ||
173 | }, | ||
174 | [ C(OP_WRITE) ] = { | ||
175 | [ C(RESULT_ACCESS) ] = -1, | ||
176 | [ C(RESULT_MISS) ] = -1, | ||
177 | }, | ||
178 | [ C(OP_PREFETCH) ] = { | ||
179 | [ C(RESULT_ACCESS) ] = -1, | ||
180 | [ C(RESULT_MISS) ] = -1, | ||
181 | }, | ||
182 | }, | ||
183 | }; | ||
184 | |||
185 | static int sh7750_event_map(int event) | ||
186 | { | ||
187 | return sh7750_general_events[event]; | ||
188 | } | ||
189 | |||
190 | static u64 sh7750_pmu_read(int idx) | ||
191 | { | ||
192 | return (u64)((u64)(__raw_readl(PMCTRH(idx)) & 0xffff) << 32) | | ||
193 | __raw_readl(PMCTRL(idx)); | ||
194 | } | ||
195 | |||
196 | static void sh7750_pmu_disable(struct hw_perf_event *hwc, int idx) | ||
197 | { | ||
198 | unsigned int tmp; | ||
199 | |||
200 | tmp = __raw_readw(PMCR(idx)); | ||
201 | tmp &= ~(PMCR_PMM_MASK | PMCR_PMEN); | ||
202 | __raw_writew(tmp, PMCR(idx)); | ||
203 | } | ||
204 | |||
205 | static void sh7750_pmu_enable(struct hw_perf_event *hwc, int idx) | ||
206 | { | ||
207 | __raw_writew(__raw_readw(PMCR(idx)) | PMCR_PMCLR, PMCR(idx)); | ||
208 | __raw_writew(hwc->config | PMCR_PMEN | PMCR_PMST, PMCR(idx)); | ||
209 | } | ||
210 | |||
211 | static void sh7750_pmu_disable_all(void) | ||
212 | { | ||
213 | int i; | ||
214 | |||
215 | for (i = 0; i < sh7750_pmu.num_events; i++) | ||
216 | __raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i)); | ||
217 | } | ||
218 | |||
219 | static void sh7750_pmu_enable_all(void) | ||
220 | { | ||
221 | int i; | ||
222 | |||
223 | for (i = 0; i < sh7750_pmu.num_events; i++) | ||
224 | __raw_writew(__raw_readw(PMCR(i)) | PMCR_PMEN, PMCR(i)); | ||
225 | } | ||
226 | |||
227 | static struct sh_pmu sh7750_pmu = { | ||
228 | .name = "SH7750", | ||
229 | .num_events = 2, | ||
230 | .event_map = sh7750_event_map, | ||
231 | .max_events = ARRAY_SIZE(sh7750_general_events), | ||
232 | .raw_event_mask = PMCR_PMM_MASK, | ||
233 | .cache_events = &sh7750_cache_events, | ||
234 | .read = sh7750_pmu_read, | ||
235 | .disable = sh7750_pmu_disable, | ||
236 | .enable = sh7750_pmu_enable, | ||
237 | .disable_all = sh7750_pmu_disable_all, | ||
238 | .enable_all = sh7750_pmu_enable_all, | ||
239 | }; | ||
240 | |||
241 | static int __init sh7750_pmu_init(void) | ||
242 | { | ||
243 | /* | ||
244 | * Make sure this CPU actually has perf counters. | ||
245 | */ | ||
246 | if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) { | ||
247 | pr_notice("HW perf events unsupported, software events only.\n"); | ||
248 | return -ENODEV; | ||
249 | } | ||
250 | |||
251 | return register_sh_pmu(&sh7750_pmu); | ||
252 | } | ||
253 | arch_initcall(sh7750_pmu_init); | ||
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile index 490d5dc9e372..33bab477d2e2 100644 --- a/arch/sh/kernel/cpu/sh4a/Makefile +++ b/arch/sh/kernel/cpu/sh4a/Makefile | |||
@@ -44,3 +44,4 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o | |||
44 | obj-y += $(clock-y) | 44 | obj-y += $(clock-y) |
45 | obj-$(CONFIG_SMP) += $(smp-y) | 45 | obj-$(CONFIG_SMP) += $(smp-y) |
46 | obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y) | 46 | obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y) |
47 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o | ||
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c index dfe9192be63e..9db743802f06 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c | |||
@@ -152,7 +152,7 @@ struct clk div6_clks[] = { | |||
152 | SH_CLK_DIV6("fsia_clk", &div3_clk, FCLKACR, 0), | 152 | SH_CLK_DIV6("fsia_clk", &div3_clk, FCLKACR, 0), |
153 | SH_CLK_DIV6("fsib_clk", &div3_clk, FCLKBCR, 0), | 153 | SH_CLK_DIV6("fsib_clk", &div3_clk, FCLKBCR, 0), |
154 | SH_CLK_DIV6("irda_clk", &div3_clk, IRDACLKCR, 0), | 154 | SH_CLK_DIV6("irda_clk", &div3_clk, IRDACLKCR, 0), |
155 | SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, 0), | 155 | SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT), |
156 | }; | 156 | }; |
157 | 157 | ||
158 | #define R_CLK (&r_clk) | 158 | #define R_CLK (&r_clk) |
diff --git a/arch/sh/kernel/cpu/sh4a/perf_event.c b/arch/sh/kernel/cpu/sh4a/perf_event.c new file mode 100644 index 000000000000..eddc21973fa1 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/perf_event.c | |||
@@ -0,0 +1,269 @@ | |||
1 | /* | ||
2 | * Performance events support for SH-4A performance counters | ||
3 | * | ||
4 | * Copyright (C) 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/irq.h> | ||
14 | #include <linux/perf_event.h> | ||
15 | #include <asm/processor.h> | ||
16 | |||
17 | #define PPC_CCBR(idx) (0xff200800 + (sizeof(u32) * idx)) | ||
18 | #define PPC_PMCTR(idx) (0xfc100000 + (sizeof(u32) * idx)) | ||
19 | |||
20 | #define CCBR_CIT_MASK (0x7ff << 6) | ||
21 | #define CCBR_DUC (1 << 3) | ||
22 | #define CCBR_CMDS (1 << 1) | ||
23 | #define CCBR_PPCE (1 << 0) | ||
24 | |||
25 | #define PPC_PMCAT 0xfc100080 | ||
26 | |||
27 | #define PMCAT_OVF3 (1 << 27) | ||
28 | #define PMCAT_CNN3 (1 << 26) | ||
29 | #define PMCAT_CLR3 (1 << 25) | ||
30 | #define PMCAT_OVF2 (1 << 19) | ||
31 | #define PMCAT_CLR2 (1 << 17) | ||
32 | #define PMCAT_OVF1 (1 << 11) | ||
33 | #define PMCAT_CNN1 (1 << 10) | ||
34 | #define PMCAT_CLR1 (1 << 9) | ||
35 | #define PMCAT_OVF0 (1 << 3) | ||
36 | #define PMCAT_CLR0 (1 << 1) | ||
37 | |||
38 | static struct sh_pmu sh4a_pmu; | ||
39 | |||
40 | /* | ||
41 | * Supported raw event codes: | ||
42 | * | ||
43 | * Event Code Description | ||
44 | * ---------- ----------- | ||
45 | * | ||
46 | * 0x0000 number of elapsed cycles | ||
47 | * 0x0200 number of elapsed cycles in privileged mode | ||
48 | * 0x0280 number of elapsed cycles while SR.BL is asserted | ||
49 | * 0x0202 instruction execution | ||
50 | * 0x0203 instruction execution in parallel | ||
51 | * 0x0204 number of unconditional branches | ||
52 | * 0x0208 number of exceptions | ||
53 | * 0x0209 number of interrupts | ||
54 | * 0x0220 UTLB miss caused by instruction fetch | ||
55 | * 0x0222 UTLB miss caused by operand access | ||
56 | * 0x02a0 number of ITLB misses | ||
57 | * 0x0028 number of accesses to instruction memories | ||
58 | * 0x0029 number of accesses to instruction cache | ||
59 | * 0x002a instruction cache miss | ||
60 | * 0x022e number of access to instruction X/Y memory | ||
61 | * 0x0030 number of reads to operand memories | ||
62 | * 0x0038 number of writes to operand memories | ||
63 | * 0x0031 number of operand cache read accesses | ||
64 | * 0x0039 number of operand cache write accesses | ||
65 | * 0x0032 operand cache read miss | ||
66 | * 0x003a operand cache write miss | ||
67 | * 0x0236 number of reads to operand X/Y memory | ||
68 | * 0x023e number of writes to operand X/Y memory | ||
69 | * 0x0237 number of reads to operand U memory | ||
70 | * 0x023f number of writes to operand U memory | ||
71 | * 0x0337 number of U memory read buffer misses | ||
72 | * 0x02b4 number of wait cycles due to operand read access | ||
73 | * 0x02bc number of wait cycles due to operand write access | ||
74 | * 0x0033 number of wait cycles due to operand cache read miss | ||
75 | * 0x003b number of wait cycles due to operand cache write miss | ||
76 | */ | ||
77 | |||
78 | /* | ||
79 | * Special reserved bits used by hardware emulators, read values will | ||
80 | * vary, but writes must always be 0. | ||
81 | */ | ||
82 | #define PMCAT_EMU_CLR_MASK ((1 << 24) | (1 << 16) | (1 << 8) | (1 << 0)) | ||
83 | |||
84 | static const int sh4a_general_events[] = { | ||
85 | [PERF_COUNT_HW_CPU_CYCLES] = 0x0000, | ||
86 | [PERF_COUNT_HW_INSTRUCTIONS] = 0x0202, | ||
87 | [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0029, /* I-cache */ | ||
88 | [PERF_COUNT_HW_CACHE_MISSES] = 0x002a, /* I-cache */ | ||
89 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0204, | ||
90 | [PERF_COUNT_HW_BRANCH_MISSES] = -1, | ||
91 | [PERF_COUNT_HW_BUS_CYCLES] = -1, | ||
92 | }; | ||
93 | |||
94 | #define C(x) PERF_COUNT_HW_CACHE_##x | ||
95 | |||
96 | static const int sh4a_cache_events | ||
97 | [PERF_COUNT_HW_CACHE_MAX] | ||
98 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
99 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = | ||
100 | { | ||
101 | [ C(L1D) ] = { | ||
102 | [ C(OP_READ) ] = { | ||
103 | [ C(RESULT_ACCESS) ] = 0x0031, | ||
104 | [ C(RESULT_MISS) ] = 0x0032, | ||
105 | }, | ||
106 | [ C(OP_WRITE) ] = { | ||
107 | [ C(RESULT_ACCESS) ] = 0x0039, | ||
108 | [ C(RESULT_MISS) ] = 0x003a, | ||
109 | }, | ||
110 | [ C(OP_PREFETCH) ] = { | ||
111 | [ C(RESULT_ACCESS) ] = 0, | ||
112 | [ C(RESULT_MISS) ] = 0, | ||
113 | }, | ||
114 | }, | ||
115 | |||
116 | [ C(L1I) ] = { | ||
117 | [ C(OP_READ) ] = { | ||
118 | [ C(RESULT_ACCESS) ] = 0x0029, | ||
119 | [ C(RESULT_MISS) ] = 0x002a, | ||
120 | }, | ||
121 | [ C(OP_WRITE) ] = { | ||
122 | [ C(RESULT_ACCESS) ] = -1, | ||
123 | [ C(RESULT_MISS) ] = -1, | ||
124 | }, | ||
125 | [ C(OP_PREFETCH) ] = { | ||
126 | [ C(RESULT_ACCESS) ] = 0, | ||
127 | [ C(RESULT_MISS) ] = 0, | ||
128 | }, | ||
129 | }, | ||
130 | |||
131 | [ C(LL) ] = { | ||
132 | [ C(OP_READ) ] = { | ||
133 | [ C(RESULT_ACCESS) ] = 0x0030, | ||
134 | [ C(RESULT_MISS) ] = 0, | ||
135 | }, | ||
136 | [ C(OP_WRITE) ] = { | ||
137 | [ C(RESULT_ACCESS) ] = 0x0038, | ||
138 | [ C(RESULT_MISS) ] = 0, | ||
139 | }, | ||
140 | [ C(OP_PREFETCH) ] = { | ||
141 | [ C(RESULT_ACCESS) ] = 0, | ||
142 | [ C(RESULT_MISS) ] = 0, | ||
143 | }, | ||
144 | }, | ||
145 | |||
146 | [ C(DTLB) ] = { | ||
147 | [ C(OP_READ) ] = { | ||
148 | [ C(RESULT_ACCESS) ] = 0x0222, | ||
149 | [ C(RESULT_MISS) ] = 0x0220, | ||
150 | }, | ||
151 | [ C(OP_WRITE) ] = { | ||
152 | [ C(RESULT_ACCESS) ] = 0, | ||
153 | [ C(RESULT_MISS) ] = 0, | ||
154 | }, | ||
155 | [ C(OP_PREFETCH) ] = { | ||
156 | [ C(RESULT_ACCESS) ] = 0, | ||
157 | [ C(RESULT_MISS) ] = 0, | ||
158 | }, | ||
159 | }, | ||
160 | |||
161 | [ C(ITLB) ] = { | ||
162 | [ C(OP_READ) ] = { | ||
163 | [ C(RESULT_ACCESS) ] = 0, | ||
164 | [ C(RESULT_MISS) ] = 0x02a0, | ||
165 | }, | ||
166 | [ C(OP_WRITE) ] = { | ||
167 | [ C(RESULT_ACCESS) ] = -1, | ||
168 | [ C(RESULT_MISS) ] = -1, | ||
169 | }, | ||
170 | [ C(OP_PREFETCH) ] = { | ||
171 | [ C(RESULT_ACCESS) ] = -1, | ||
172 | [ C(RESULT_MISS) ] = -1, | ||
173 | }, | ||
174 | }, | ||
175 | |||
176 | [ C(BPU) ] = { | ||
177 | [ C(OP_READ) ] = { | ||
178 | [ C(RESULT_ACCESS) ] = -1, | ||
179 | [ C(RESULT_MISS) ] = -1, | ||
180 | }, | ||
181 | [ C(OP_WRITE) ] = { | ||
182 | [ C(RESULT_ACCESS) ] = -1, | ||
183 | [ C(RESULT_MISS) ] = -1, | ||
184 | }, | ||
185 | [ C(OP_PREFETCH) ] = { | ||
186 | [ C(RESULT_ACCESS) ] = -1, | ||
187 | [ C(RESULT_MISS) ] = -1, | ||
188 | }, | ||
189 | }, | ||
190 | }; | ||
191 | |||
192 | static int sh4a_event_map(int event) | ||
193 | { | ||
194 | return sh4a_general_events[event]; | ||
195 | } | ||
196 | |||
197 | static u64 sh4a_pmu_read(int idx) | ||
198 | { | ||
199 | return __raw_readl(PPC_PMCTR(idx)); | ||
200 | } | ||
201 | |||
202 | static void sh4a_pmu_disable(struct hw_perf_event *hwc, int idx) | ||
203 | { | ||
204 | unsigned int tmp; | ||
205 | |||
206 | tmp = __raw_readl(PPC_CCBR(idx)); | ||
207 | tmp &= ~(CCBR_CIT_MASK | CCBR_DUC); | ||
208 | __raw_writel(tmp, PPC_CCBR(idx)); | ||
209 | } | ||
210 | |||
211 | static void sh4a_pmu_enable(struct hw_perf_event *hwc, int idx) | ||
212 | { | ||
213 | unsigned int tmp; | ||
214 | |||
215 | tmp = __raw_readl(PPC_PMCAT); | ||
216 | tmp &= ~PMCAT_EMU_CLR_MASK; | ||
217 | tmp |= idx ? PMCAT_CLR1 : PMCAT_CLR0; | ||
218 | __raw_writel(tmp, PPC_PMCAT); | ||
219 | |||
220 | tmp = __raw_readl(PPC_CCBR(idx)); | ||
221 | tmp |= (hwc->config << 6) | CCBR_CMDS | CCBR_PPCE; | ||
222 | __raw_writel(tmp, PPC_CCBR(idx)); | ||
223 | |||
224 | __raw_writel(__raw_readl(PPC_CCBR(idx)) | CCBR_DUC, PPC_CCBR(idx)); | ||
225 | } | ||
226 | |||
227 | static void sh4a_pmu_disable_all(void) | ||
228 | { | ||
229 | int i; | ||
230 | |||
231 | for (i = 0; i < sh4a_pmu.num_events; i++) | ||
232 | __raw_writel(__raw_readl(PPC_CCBR(i)) & ~CCBR_DUC, PPC_CCBR(i)); | ||
233 | } | ||
234 | |||
235 | static void sh4a_pmu_enable_all(void) | ||
236 | { | ||
237 | int i; | ||
238 | |||
239 | for (i = 0; i < sh4a_pmu.num_events; i++) | ||
240 | __raw_writel(__raw_readl(PPC_CCBR(i)) | CCBR_DUC, PPC_CCBR(i)); | ||
241 | } | ||
242 | |||
243 | static struct sh_pmu sh4a_pmu = { | ||
244 | .name = "SH-4A", | ||
245 | .num_events = 2, | ||
246 | .event_map = sh4a_event_map, | ||
247 | .max_events = ARRAY_SIZE(sh4a_general_events), | ||
248 | .raw_event_mask = 0x3ff, | ||
249 | .cache_events = &sh4a_cache_events, | ||
250 | .read = sh4a_pmu_read, | ||
251 | .disable = sh4a_pmu_disable, | ||
252 | .enable = sh4a_pmu_enable, | ||
253 | .disable_all = sh4a_pmu_disable_all, | ||
254 | .enable_all = sh4a_pmu_enable_all, | ||
255 | }; | ||
256 | |||
257 | static int __init sh4a_pmu_init(void) | ||
258 | { | ||
259 | /* | ||
260 | * Make sure this CPU actually has perf counters. | ||
261 | */ | ||
262 | if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) { | ||
263 | pr_notice("HW perf events unsupported, software events only.\n"); | ||
264 | return -ENODEV; | ||
265 | } | ||
266 | |||
267 | return register_sh_pmu(&sh4a_pmu); | ||
268 | } | ||
269 | arch_initcall(sh4a_pmu_init); | ||
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c index f3851fd757ec..845e89c936e7 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/uio_driver.h> | 20 | #include <linux/uio_driver.h> |
21 | #include <linux/sh_timer.h> | 21 | #include <linux/sh_timer.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/notifier.h> | ||
24 | #include <asm/suspend.h> | ||
23 | #include <asm/clock.h> | 25 | #include <asm/clock.h> |
24 | #include <asm/mmzone.h> | 26 | #include <asm/mmzone.h> |
25 | #include <cpu/sh7724.h> | 27 | #include <cpu/sh7724.h> |
@@ -202,7 +204,7 @@ static struct resource veu0_resources[] = { | |||
202 | [0] = { | 204 | [0] = { |
203 | .name = "VEU3F0", | 205 | .name = "VEU3F0", |
204 | .start = 0xfe920000, | 206 | .start = 0xfe920000, |
205 | .end = 0xfe9200cb - 1, | 207 | .end = 0xfe9200cb, |
206 | .flags = IORESOURCE_MEM, | 208 | .flags = IORESOURCE_MEM, |
207 | }, | 209 | }, |
208 | [1] = { | 210 | [1] = { |
@@ -234,7 +236,7 @@ static struct resource veu1_resources[] = { | |||
234 | [0] = { | 236 | [0] = { |
235 | .name = "VEU3F1", | 237 | .name = "VEU3F1", |
236 | .start = 0xfe924000, | 238 | .start = 0xfe924000, |
237 | .end = 0xfe9240cb - 1, | 239 | .end = 0xfe9240cb, |
238 | .flags = IORESOURCE_MEM, | 240 | .flags = IORESOURCE_MEM, |
239 | }, | 241 | }, |
240 | [1] = { | 242 | [1] = { |
@@ -523,6 +525,70 @@ static struct platform_device jpu_device = { | |||
523 | }, | 525 | }, |
524 | }; | 526 | }; |
525 | 527 | ||
528 | /* SPU2DSP0 */ | ||
529 | static struct uio_info spu0_platform_data = { | ||
530 | .name = "SPU2DSP0", | ||
531 | .version = "0", | ||
532 | .irq = 86, | ||
533 | }; | ||
534 | |||
535 | static struct resource spu0_resources[] = { | ||
536 | [0] = { | ||
537 | .name = "SPU2DSP0", | ||
538 | .start = 0xFE200000, | ||
539 | .end = 0xFE2FFFFF, | ||
540 | .flags = IORESOURCE_MEM, | ||
541 | }, | ||
542 | [1] = { | ||
543 | /* place holder for contiguous memory */ | ||
544 | }, | ||
545 | }; | ||
546 | |||
547 | static struct platform_device spu0_device = { | ||
548 | .name = "uio_pdrv_genirq", | ||
549 | .id = 4, | ||
550 | .dev = { | ||
551 | .platform_data = &spu0_platform_data, | ||
552 | }, | ||
553 | .resource = spu0_resources, | ||
554 | .num_resources = ARRAY_SIZE(spu0_resources), | ||
555 | .archdata = { | ||
556 | .hwblk_id = HWBLK_SPU, | ||
557 | }, | ||
558 | }; | ||
559 | |||
560 | /* SPU2DSP1 */ | ||
561 | static struct uio_info spu1_platform_data = { | ||
562 | .name = "SPU2DSP1", | ||
563 | .version = "0", | ||
564 | .irq = 87, | ||
565 | }; | ||
566 | |||
567 | static struct resource spu1_resources[] = { | ||
568 | [0] = { | ||
569 | .name = "SPU2DSP1", | ||
570 | .start = 0xFE300000, | ||
571 | .end = 0xFE3FFFFF, | ||
572 | .flags = IORESOURCE_MEM, | ||
573 | }, | ||
574 | [1] = { | ||
575 | /* place holder for contiguous memory */ | ||
576 | }, | ||
577 | }; | ||
578 | |||
579 | static struct platform_device spu1_device = { | ||
580 | .name = "uio_pdrv_genirq", | ||
581 | .id = 5, | ||
582 | .dev = { | ||
583 | .platform_data = &spu1_platform_data, | ||
584 | }, | ||
585 | .resource = spu1_resources, | ||
586 | .num_resources = ARRAY_SIZE(spu1_resources), | ||
587 | .archdata = { | ||
588 | .hwblk_id = HWBLK_SPU, | ||
589 | }, | ||
590 | }; | ||
591 | |||
526 | static struct platform_device *sh7724_devices[] __initdata = { | 592 | static struct platform_device *sh7724_devices[] __initdata = { |
527 | &cmt_device, | 593 | &cmt_device, |
528 | &tmu0_device, | 594 | &tmu0_device, |
@@ -539,6 +605,8 @@ static struct platform_device *sh7724_devices[] __initdata = { | |||
539 | &veu0_device, | 605 | &veu0_device, |
540 | &veu1_device, | 606 | &veu1_device, |
541 | &jpu_device, | 607 | &jpu_device, |
608 | &spu0_device, | ||
609 | &spu1_device, | ||
542 | }; | 610 | }; |
543 | 611 | ||
544 | static int __init sh7724_devices_setup(void) | 612 | static int __init sh7724_devices_setup(void) |
@@ -547,6 +615,8 @@ static int __init sh7724_devices_setup(void) | |||
547 | platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20); | 615 | platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20); |
548 | platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20); | 616 | platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20); |
549 | platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20); | 617 | platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20); |
618 | platform_resource_setup_memory(&spu0_device, "spu0", 2 << 20); | ||
619 | platform_resource_setup_memory(&spu1_device, "spu1", 2 << 20); | ||
550 | 620 | ||
551 | return platform_add_devices(sh7724_devices, | 621 | return platform_add_devices(sh7724_devices, |
552 | ARRAY_SIZE(sh7724_devices)); | 622 | ARRAY_SIZE(sh7724_devices)); |
@@ -827,3 +897,193 @@ void __init plat_irq_setup(void) | |||
827 | { | 897 | { |
828 | register_intc_controller(&intc_desc); | 898 | register_intc_controller(&intc_desc); |
829 | } | 899 | } |
900 | |||
901 | static struct { | ||
902 | /* BSC */ | ||
903 | unsigned long mmselr; | ||
904 | unsigned long cs0bcr; | ||
905 | unsigned long cs4bcr; | ||
906 | unsigned long cs5abcr; | ||
907 | unsigned long cs5bbcr; | ||
908 | unsigned long cs6abcr; | ||
909 | unsigned long cs6bbcr; | ||
910 | unsigned long cs4wcr; | ||
911 | unsigned long cs5awcr; | ||
912 | unsigned long cs5bwcr; | ||
913 | unsigned long cs6awcr; | ||
914 | unsigned long cs6bwcr; | ||
915 | /* INTC */ | ||
916 | unsigned short ipra; | ||
917 | unsigned short iprb; | ||
918 | unsigned short iprc; | ||
919 | unsigned short iprd; | ||
920 | unsigned short ipre; | ||
921 | unsigned short iprf; | ||
922 | unsigned short iprg; | ||
923 | unsigned short iprh; | ||
924 | unsigned short ipri; | ||
925 | unsigned short iprj; | ||
926 | unsigned short iprk; | ||
927 | unsigned short iprl; | ||
928 | unsigned char imr0; | ||
929 | unsigned char imr1; | ||
930 | unsigned char imr2; | ||
931 | unsigned char imr3; | ||
932 | unsigned char imr4; | ||
933 | unsigned char imr5; | ||
934 | unsigned char imr6; | ||
935 | unsigned char imr7; | ||
936 | unsigned char imr8; | ||
937 | unsigned char imr9; | ||
938 | unsigned char imr10; | ||
939 | unsigned char imr11; | ||
940 | unsigned char imr12; | ||
941 | /* RWDT */ | ||
942 | unsigned short rwtcnt; | ||
943 | unsigned short rwtcsr; | ||
944 | /* CPG */ | ||
945 | unsigned long irdaclk; | ||
946 | unsigned long spuclk; | ||
947 | } sh7724_rstandby_state; | ||
948 | |||
949 | static int sh7724_pre_sleep_notifier_call(struct notifier_block *nb, | ||
950 | unsigned long flags, void *unused) | ||
951 | { | ||
952 | if (!(flags & SUSP_SH_RSTANDBY)) | ||
953 | return NOTIFY_DONE; | ||
954 | |||
955 | /* BCR */ | ||
956 | sh7724_rstandby_state.mmselr = __raw_readl(0xff800020); /* MMSELR */ | ||
957 | sh7724_rstandby_state.mmselr |= 0xa5a50000; | ||
958 | sh7724_rstandby_state.cs0bcr = __raw_readl(0xfec10004); /* CS0BCR */ | ||
959 | sh7724_rstandby_state.cs4bcr = __raw_readl(0xfec10010); /* CS4BCR */ | ||
960 | sh7724_rstandby_state.cs5abcr = __raw_readl(0xfec10014); /* CS5ABCR */ | ||
961 | sh7724_rstandby_state.cs5bbcr = __raw_readl(0xfec10018); /* CS5BBCR */ | ||
962 | sh7724_rstandby_state.cs6abcr = __raw_readl(0xfec1001c); /* CS6ABCR */ | ||
963 | sh7724_rstandby_state.cs6bbcr = __raw_readl(0xfec10020); /* CS6BBCR */ | ||
964 | sh7724_rstandby_state.cs4wcr = __raw_readl(0xfec10030); /* CS4WCR */ | ||
965 | sh7724_rstandby_state.cs5awcr = __raw_readl(0xfec10034); /* CS5AWCR */ | ||
966 | sh7724_rstandby_state.cs5bwcr = __raw_readl(0xfec10038); /* CS5BWCR */ | ||
967 | sh7724_rstandby_state.cs6awcr = __raw_readl(0xfec1003c); /* CS6AWCR */ | ||
968 | sh7724_rstandby_state.cs6bwcr = __raw_readl(0xfec10040); /* CS6BWCR */ | ||
969 | |||
970 | /* INTC */ | ||
971 | sh7724_rstandby_state.ipra = __raw_readw(0xa4080000); /* IPRA */ | ||
972 | sh7724_rstandby_state.iprb = __raw_readw(0xa4080004); /* IPRB */ | ||
973 | sh7724_rstandby_state.iprc = __raw_readw(0xa4080008); /* IPRC */ | ||
974 | sh7724_rstandby_state.iprd = __raw_readw(0xa408000c); /* IPRD */ | ||
975 | sh7724_rstandby_state.ipre = __raw_readw(0xa4080010); /* IPRE */ | ||
976 | sh7724_rstandby_state.iprf = __raw_readw(0xa4080014); /* IPRF */ | ||
977 | sh7724_rstandby_state.iprg = __raw_readw(0xa4080018); /* IPRG */ | ||
978 | sh7724_rstandby_state.iprh = __raw_readw(0xa408001c); /* IPRH */ | ||
979 | sh7724_rstandby_state.ipri = __raw_readw(0xa4080020); /* IPRI */ | ||
980 | sh7724_rstandby_state.iprj = __raw_readw(0xa4080024); /* IPRJ */ | ||
981 | sh7724_rstandby_state.iprk = __raw_readw(0xa4080028); /* IPRK */ | ||
982 | sh7724_rstandby_state.iprl = __raw_readw(0xa408002c); /* IPRL */ | ||
983 | sh7724_rstandby_state.imr0 = __raw_readb(0xa4080080); /* IMR0 */ | ||
984 | sh7724_rstandby_state.imr1 = __raw_readb(0xa4080084); /* IMR1 */ | ||
985 | sh7724_rstandby_state.imr2 = __raw_readb(0xa4080088); /* IMR2 */ | ||
986 | sh7724_rstandby_state.imr3 = __raw_readb(0xa408008c); /* IMR3 */ | ||
987 | sh7724_rstandby_state.imr4 = __raw_readb(0xa4080090); /* IMR4 */ | ||
988 | sh7724_rstandby_state.imr5 = __raw_readb(0xa4080094); /* IMR5 */ | ||
989 | sh7724_rstandby_state.imr6 = __raw_readb(0xa4080098); /* IMR6 */ | ||
990 | sh7724_rstandby_state.imr7 = __raw_readb(0xa408009c); /* IMR7 */ | ||
991 | sh7724_rstandby_state.imr8 = __raw_readb(0xa40800a0); /* IMR8 */ | ||
992 | sh7724_rstandby_state.imr9 = __raw_readb(0xa40800a4); /* IMR9 */ | ||
993 | sh7724_rstandby_state.imr10 = __raw_readb(0xa40800a8); /* IMR10 */ | ||
994 | sh7724_rstandby_state.imr11 = __raw_readb(0xa40800ac); /* IMR11 */ | ||
995 | sh7724_rstandby_state.imr12 = __raw_readb(0xa40800b0); /* IMR12 */ | ||
996 | |||
997 | /* RWDT */ | ||
998 | sh7724_rstandby_state.rwtcnt = __raw_readb(0xa4520000); /* RWTCNT */ | ||
999 | sh7724_rstandby_state.rwtcnt |= 0x5a00; | ||
1000 | sh7724_rstandby_state.rwtcsr = __raw_readb(0xa4520004); /* RWTCSR */ | ||
1001 | sh7724_rstandby_state.rwtcsr |= 0xa500; | ||
1002 | __raw_writew(sh7724_rstandby_state.rwtcsr & 0x07, 0xa4520004); | ||
1003 | |||
1004 | /* CPG */ | ||
1005 | sh7724_rstandby_state.irdaclk = __raw_readl(0xa4150018); /* IRDACLKCR */ | ||
1006 | sh7724_rstandby_state.spuclk = __raw_readl(0xa415003c); /* SPUCLKCR */ | ||
1007 | |||
1008 | return NOTIFY_DONE; | ||
1009 | } | ||
1010 | |||
1011 | static int sh7724_post_sleep_notifier_call(struct notifier_block *nb, | ||
1012 | unsigned long flags, void *unused) | ||
1013 | { | ||
1014 | if (!(flags & SUSP_SH_RSTANDBY)) | ||
1015 | return NOTIFY_DONE; | ||
1016 | |||
1017 | /* BCR */ | ||
1018 | __raw_writel(sh7724_rstandby_state.mmselr, 0xff800020); /* MMSELR */ | ||
1019 | __raw_writel(sh7724_rstandby_state.cs0bcr, 0xfec10004); /* CS0BCR */ | ||
1020 | __raw_writel(sh7724_rstandby_state.cs4bcr, 0xfec10010); /* CS4BCR */ | ||
1021 | __raw_writel(sh7724_rstandby_state.cs5abcr, 0xfec10014); /* CS5ABCR */ | ||
1022 | __raw_writel(sh7724_rstandby_state.cs5bbcr, 0xfec10018); /* CS5BBCR */ | ||
1023 | __raw_writel(sh7724_rstandby_state.cs6abcr, 0xfec1001c); /* CS6ABCR */ | ||
1024 | __raw_writel(sh7724_rstandby_state.cs6bbcr, 0xfec10020); /* CS6BBCR */ | ||
1025 | __raw_writel(sh7724_rstandby_state.cs4wcr, 0xfec10030); /* CS4WCR */ | ||
1026 | __raw_writel(sh7724_rstandby_state.cs5awcr, 0xfec10034); /* CS5AWCR */ | ||
1027 | __raw_writel(sh7724_rstandby_state.cs5bwcr, 0xfec10038); /* CS5BWCR */ | ||
1028 | __raw_writel(sh7724_rstandby_state.cs6awcr, 0xfec1003c); /* CS6AWCR */ | ||
1029 | __raw_writel(sh7724_rstandby_state.cs6bwcr, 0xfec10040); /* CS6BWCR */ | ||
1030 | |||
1031 | /* INTC */ | ||
1032 | __raw_writew(sh7724_rstandby_state.ipra, 0xa4080000); /* IPRA */ | ||
1033 | __raw_writew(sh7724_rstandby_state.iprb, 0xa4080004); /* IPRB */ | ||
1034 | __raw_writew(sh7724_rstandby_state.iprc, 0xa4080008); /* IPRC */ | ||
1035 | __raw_writew(sh7724_rstandby_state.iprd, 0xa408000c); /* IPRD */ | ||
1036 | __raw_writew(sh7724_rstandby_state.ipre, 0xa4080010); /* IPRE */ | ||
1037 | __raw_writew(sh7724_rstandby_state.iprf, 0xa4080014); /* IPRF */ | ||
1038 | __raw_writew(sh7724_rstandby_state.iprg, 0xa4080018); /* IPRG */ | ||
1039 | __raw_writew(sh7724_rstandby_state.iprh, 0xa408001c); /* IPRH */ | ||
1040 | __raw_writew(sh7724_rstandby_state.ipri, 0xa4080020); /* IPRI */ | ||
1041 | __raw_writew(sh7724_rstandby_state.iprj, 0xa4080024); /* IPRJ */ | ||
1042 | __raw_writew(sh7724_rstandby_state.iprk, 0xa4080028); /* IPRK */ | ||
1043 | __raw_writew(sh7724_rstandby_state.iprl, 0xa408002c); /* IPRL */ | ||
1044 | __raw_writeb(sh7724_rstandby_state.imr0, 0xa4080080); /* IMR0 */ | ||
1045 | __raw_writeb(sh7724_rstandby_state.imr1, 0xa4080084); /* IMR1 */ | ||
1046 | __raw_writeb(sh7724_rstandby_state.imr2, 0xa4080088); /* IMR2 */ | ||
1047 | __raw_writeb(sh7724_rstandby_state.imr3, 0xa408008c); /* IMR3 */ | ||
1048 | __raw_writeb(sh7724_rstandby_state.imr4, 0xa4080090); /* IMR4 */ | ||
1049 | __raw_writeb(sh7724_rstandby_state.imr5, 0xa4080094); /* IMR5 */ | ||
1050 | __raw_writeb(sh7724_rstandby_state.imr6, 0xa4080098); /* IMR6 */ | ||
1051 | __raw_writeb(sh7724_rstandby_state.imr7, 0xa408009c); /* IMR7 */ | ||
1052 | __raw_writeb(sh7724_rstandby_state.imr8, 0xa40800a0); /* IMR8 */ | ||
1053 | __raw_writeb(sh7724_rstandby_state.imr9, 0xa40800a4); /* IMR9 */ | ||
1054 | __raw_writeb(sh7724_rstandby_state.imr10, 0xa40800a8); /* IMR10 */ | ||
1055 | __raw_writeb(sh7724_rstandby_state.imr11, 0xa40800ac); /* IMR11 */ | ||
1056 | __raw_writeb(sh7724_rstandby_state.imr12, 0xa40800b0); /* IMR12 */ | ||
1057 | |||
1058 | /* RWDT */ | ||
1059 | __raw_writew(sh7724_rstandby_state.rwtcnt, 0xa4520000); /* RWTCNT */ | ||
1060 | __raw_writew(sh7724_rstandby_state.rwtcsr, 0xa4520004); /* RWTCSR */ | ||
1061 | |||
1062 | /* CPG */ | ||
1063 | __raw_writel(sh7724_rstandby_state.irdaclk, 0xa4150018); /* IRDACLKCR */ | ||
1064 | __raw_writel(sh7724_rstandby_state.spuclk, 0xa415003c); /* SPUCLKCR */ | ||
1065 | |||
1066 | return NOTIFY_DONE; | ||
1067 | } | ||
1068 | |||
1069 | static struct notifier_block sh7724_pre_sleep_notifier = { | ||
1070 | .notifier_call = sh7724_pre_sleep_notifier_call, | ||
1071 | .priority = SH_MOBILE_PRE(SH_MOBILE_SLEEP_CPU), | ||
1072 | }; | ||
1073 | |||
1074 | static struct notifier_block sh7724_post_sleep_notifier = { | ||
1075 | .notifier_call = sh7724_post_sleep_notifier_call, | ||
1076 | .priority = SH_MOBILE_POST(SH_MOBILE_SLEEP_CPU), | ||
1077 | }; | ||
1078 | |||
1079 | static int __init sh7724_sleep_setup(void) | ||
1080 | { | ||
1081 | atomic_notifier_chain_register(&sh_mobile_pre_sleep_notifier_list, | ||
1082 | &sh7724_pre_sleep_notifier); | ||
1083 | |||
1084 | atomic_notifier_chain_register(&sh_mobile_post_sleep_notifier_list, | ||
1085 | &sh7724_post_sleep_notifier); | ||
1086 | return 0; | ||
1087 | } | ||
1088 | arch_initcall(sh7724_sleep_setup); | ||
1089 | |||
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c index e848443deeb9..c7ba9166e18a 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c | |||
@@ -15,6 +15,15 @@ | |||
15 | #include <linux/sh_timer.h> | 15 | #include <linux/sh_timer.h> |
16 | #include <asm/mmzone.h> | 16 | #include <asm/mmzone.h> |
17 | 17 | ||
18 | /* | ||
19 | * This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2 | ||
20 | * INTEVT values overlap with the FPU EXPEVT ones, requiring special | ||
21 | * demuxing in the exception dispatch path. | ||
22 | * | ||
23 | * As this overlap is something that never should have made it in to | ||
24 | * silicon in the first place, we just refuse to deal with the port at | ||
25 | * all rather than adding infrastructure to hack around it. | ||
26 | */ | ||
18 | static struct plat_sci_port sci_platform_data[] = { | 27 | static struct plat_sci_port sci_platform_data[] = { |
19 | { | 28 | { |
20 | .mapbase = 0xffc30000, | 29 | .mapbase = 0xffc30000, |
@@ -27,11 +36,6 @@ static struct plat_sci_port sci_platform_data[] = { | |||
27 | .type = PORT_SCIF, | 36 | .type = PORT_SCIF, |
28 | .irqs = { 44, 45, 47, 46 }, | 37 | .irqs = { 44, 45, 47, 46 }, |
29 | }, { | 38 | }, { |
30 | .mapbase = 0xffc50000, | ||
31 | .flags = UPF_BOOT_AUTOCONF, | ||
32 | .type = PORT_SCIF, | ||
33 | .irqs = { 48, 49, 51, 50 }, | ||
34 | }, { | ||
35 | .mapbase = 0xffc60000, | 39 | .mapbase = 0xffc60000, |
36 | .flags = UPF_BOOT_AUTOCONF, | 40 | .flags = UPF_BOOT_AUTOCONF, |
37 | .type = PORT_SCIF, | 41 | .type = PORT_SCIF, |
@@ -268,7 +272,11 @@ enum { | |||
268 | UNUSED = 0, | 272 | UNUSED = 0, |
269 | 273 | ||
270 | /* interrupt sources */ | 274 | /* interrupt sources */ |
271 | IRL, IRQ0, IRQ1, IRQ2, IRQ3, | 275 | IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH, |
276 | IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH, | ||
277 | IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH, | ||
278 | IRL_HHLL, IRL_HHLH, IRL_HHHL, | ||
279 | IRQ0, IRQ1, IRQ2, IRQ3, | ||
272 | HUDII, | 280 | HUDII, |
273 | TMU0, TMU1, TMU2, TMU3, TMU4, TMU5, | 281 | TMU0, TMU1, TMU2, TMU3, TMU4, TMU5, |
274 | PCII0, PCII1, PCII2, PCII3, PCII4, | 282 | PCII0, PCII1, PCII2, PCII3, PCII4, |
@@ -291,7 +299,7 @@ enum { | |||
291 | INTICI4, INTICI5, INTICI6, INTICI7, | 299 | INTICI4, INTICI5, INTICI6, INTICI7, |
292 | 300 | ||
293 | /* interrupt groups */ | 301 | /* interrupt groups */ |
294 | PCII56789, SCIF0, SCIF1, SCIF2, SCIF3, | 302 | IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3, |
295 | DMAC0, DMAC1, | 303 | DMAC0, DMAC1, |
296 | }; | 304 | }; |
297 | 305 | ||
@@ -309,8 +317,6 @@ static struct intc_vect vectors[] __initdata = { | |||
309 | INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760), | 317 | INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760), |
310 | INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0), | 318 | INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0), |
311 | INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0), | 319 | INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0), |
312 | INTC_VECT(SCIF2_ERI, 0x800), INTC_VECT(SCIF2_RXI, 0x820), | ||
313 | INTC_VECT(SCIF2_BRI, 0x840), INTC_VECT(SCIF2_TXI, 0x860), | ||
314 | INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0), | 320 | INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0), |
315 | INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0), | 321 | INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0), |
316 | INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920), | 322 | INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920), |
@@ -344,10 +350,13 @@ static struct intc_vect vectors[] __initdata = { | |||
344 | }; | 350 | }; |
345 | 351 | ||
346 | static struct intc_group groups[] __initdata = { | 352 | static struct intc_group groups[] __initdata = { |
353 | INTC_GROUP(IRL, IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH, | ||
354 | IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH, | ||
355 | IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH, | ||
356 | IRL_HHLL, IRL_HHLH, IRL_HHHL), | ||
347 | INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9), | 357 | INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9), |
348 | INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), | 358 | INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), |
349 | INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI), | 359 | INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI), |
350 | INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI), | ||
351 | INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI), | 360 | INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI), |
352 | INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, | 361 | INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, |
353 | DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE), | 362 | DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE), |
@@ -419,14 +428,14 @@ static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups, | |||
419 | 428 | ||
420 | /* External interrupt pins in IRL mode */ | 429 | /* External interrupt pins in IRL mode */ |
421 | static struct intc_vect vectors_irl[] __initdata = { | 430 | static struct intc_vect vectors_irl[] __initdata = { |
422 | INTC_VECT(IRL, 0x200), INTC_VECT(IRL, 0x220), | 431 | INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220), |
423 | INTC_VECT(IRL, 0x240), INTC_VECT(IRL, 0x260), | 432 | INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260), |
424 | INTC_VECT(IRL, 0x280), INTC_VECT(IRL, 0x2a0), | 433 | INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0), |
425 | INTC_VECT(IRL, 0x2c0), INTC_VECT(IRL, 0x2e0), | 434 | INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0), |
426 | INTC_VECT(IRL, 0x300), INTC_VECT(IRL, 0x320), | 435 | INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320), |
427 | INTC_VECT(IRL, 0x340), INTC_VECT(IRL, 0x360), | 436 | INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360), |
428 | INTC_VECT(IRL, 0x380), INTC_VECT(IRL, 0x3a0), | 437 | INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0), |
429 | INTC_VECT(IRL, 0x3c0), | 438 | INTC_VECT(IRL_HHHL, 0x3c0), |
430 | }; | 439 | }; |
431 | 440 | ||
432 | static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups, | 441 | static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups, |
diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c index 185ec3976a25..5863e0c4d02f 100644 --- a/arch/sh/kernel/cpu/sh4a/smp-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c | |||
@@ -14,6 +14,13 @@ | |||
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
16 | 16 | ||
17 | #define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12)) | ||
18 | #define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12)) | ||
19 | |||
20 | #define STBCR_MSTP 0x00000001 | ||
21 | #define STBCR_RESET 0x00000002 | ||
22 | #define STBCR_LTSLP 0x80000000 | ||
23 | |||
17 | static irqreturn_t ipi_interrupt_handler(int irq, void *arg) | 24 | static irqreturn_t ipi_interrupt_handler(int irq, void *arg) |
18 | { | 25 | { |
19 | unsigned int message = (unsigned int)(long)arg; | 26 | unsigned int message = (unsigned int)(long)arg; |
@@ -21,9 +28,9 @@ static irqreturn_t ipi_interrupt_handler(int irq, void *arg) | |||
21 | unsigned int offs = 4 * cpu; | 28 | unsigned int offs = 4 * cpu; |
22 | unsigned int x; | 29 | unsigned int x; |
23 | 30 | ||
24 | x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */ | 31 | x = __raw_readl(0xfe410070 + offs); /* C0INITICI..CnINTICI */ |
25 | x &= (1 << (message << 2)); | 32 | x &= (1 << (message << 2)); |
26 | ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */ | 33 | __raw_writel(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */ |
27 | 34 | ||
28 | smp_message_recv(message); | 35 | smp_message_recv(message); |
29 | 36 | ||
@@ -37,6 +44,9 @@ void __init plat_smp_setup(void) | |||
37 | 44 | ||
38 | init_cpu_possible(cpumask_of(cpu)); | 45 | init_cpu_possible(cpumask_of(cpu)); |
39 | 46 | ||
47 | /* Enable light sleep for the boot CPU */ | ||
48 | __raw_writel(__raw_readl(STBCR_REG(cpu)) | STBCR_LTSLP, STBCR_REG(cpu)); | ||
49 | |||
40 | __cpu_number_map[0] = 0; | 50 | __cpu_number_map[0] = 0; |
41 | __cpu_logical_map[0] = 0; | 51 | __cpu_logical_map[0] = 0; |
42 | 52 | ||
@@ -66,32 +76,23 @@ void __init plat_prepare_cpus(unsigned int max_cpus) | |||
66 | "IPI", (void *)(long)i); | 76 | "IPI", (void *)(long)i); |
67 | } | 77 | } |
68 | 78 | ||
69 | #define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12)) | ||
70 | #define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12)) | ||
71 | |||
72 | #define STBCR_MSTP 0x00000001 | ||
73 | #define STBCR_RESET 0x00000002 | ||
74 | #define STBCR_LTSLP 0x80000000 | ||
75 | |||
76 | #define STBCR_AP_VAL (STBCR_RESET | STBCR_LTSLP) | ||
77 | |||
78 | void plat_start_cpu(unsigned int cpu, unsigned long entry_point) | 79 | void plat_start_cpu(unsigned int cpu, unsigned long entry_point) |
79 | { | 80 | { |
80 | ctrl_outl(entry_point, RESET_REG(cpu)); | 81 | __raw_writel(entry_point, RESET_REG(cpu)); |
81 | 82 | ||
82 | if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) | 83 | if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP)) |
83 | ctrl_outl(STBCR_MSTP, STBCR_REG(cpu)); | 84 | __raw_writel(STBCR_MSTP, STBCR_REG(cpu)); |
84 | 85 | ||
85 | while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) | 86 | while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP)) |
86 | cpu_relax(); | 87 | cpu_relax(); |
87 | 88 | ||
88 | /* Start up secondary processor by sending a reset */ | 89 | /* Start up secondary processor by sending a reset */ |
89 | ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu)); | 90 | __raw_writel(STBCR_RESET | STBCR_LTSLP, STBCR_REG(cpu)); |
90 | } | 91 | } |
91 | 92 | ||
92 | int plat_smp_processor_id(void) | 93 | int plat_smp_processor_id(void) |
93 | { | 94 | { |
94 | return ctrl_inl(0xff000048); /* CPIDR */ | 95 | return __raw_readl(0xff000048); /* CPIDR */ |
95 | } | 96 | } |
96 | 97 | ||
97 | void plat_send_ipi(unsigned int cpu, unsigned int message) | 98 | void plat_send_ipi(unsigned int cpu, unsigned int message) |
@@ -100,5 +101,5 @@ void plat_send_ipi(unsigned int cpu, unsigned int message) | |||
100 | 101 | ||
101 | BUG_ON(cpu >= 4); | 102 | BUG_ON(cpu >= 4); |
102 | 103 | ||
103 | ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */ | 104 | __raw_writel(1 << (message << 2), addr); /* C0INTICI..CnINTICI */ |
104 | } | 105 | } |
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S index b0aacf675258..8f13f73cb2cb 100644 --- a/arch/sh/kernel/cpu/sh5/entry.S +++ b/arch/sh/kernel/cpu/sh5/entry.S | |||
@@ -933,7 +933,7 @@ ret_with_reschedule: | |||
933 | 933 | ||
934 | pta restore_all, tr1 | 934 | pta restore_all, tr1 |
935 | 935 | ||
936 | movi (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8 | 936 | movi _TIF_SIGPENDING, r8 |
937 | and r8, r7, r8 | 937 | and r8, r7, r8 |
938 | pta work_notifysig, tr0 | 938 | pta work_notifysig, tr0 |
939 | bne r8, ZERO, tr0 | 939 | bne r8, ZERO, tr0 |
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index 1c504bd972c3..83972aa319c2 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c | |||
@@ -87,25 +87,31 @@ void sh_mobile_setup_cpuidle(void) | |||
87 | 87 | ||
88 | dev->safe_state = state; | 88 | dev->safe_state = state; |
89 | 89 | ||
90 | state = &dev->states[i++]; | 90 | if (sh_mobile_sleep_supported & SUSP_SH_SF) { |
91 | snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); | 91 | state = &dev->states[i++]; |
92 | strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN); | 92 | snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); |
93 | state->exit_latency = 100; | 93 | strncpy(state->desc, "SuperH Sleep Mode [SF]", |
94 | state->target_residency = 1 * 2; | 94 | CPUIDLE_DESC_LEN); |
95 | state->power_usage = 1; | 95 | state->exit_latency = 100; |
96 | state->flags = 0; | 96 | state->target_residency = 1 * 2; |
97 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | 97 | state->power_usage = 1; |
98 | state->enter = cpuidle_sleep_enter; | 98 | state->flags = 0; |
99 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
100 | state->enter = cpuidle_sleep_enter; | ||
101 | } | ||
99 | 102 | ||
100 | state = &dev->states[i++]; | 103 | if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) { |
101 | snprintf(state->name, CPUIDLE_NAME_LEN, "C2"); | 104 | state = &dev->states[i++]; |
102 | strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", CPUIDLE_DESC_LEN); | 105 | snprintf(state->name, CPUIDLE_NAME_LEN, "C2"); |
103 | state->exit_latency = 2300; | 106 | strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", |
104 | state->target_residency = 1 * 2; | 107 | CPUIDLE_DESC_LEN); |
105 | state->power_usage = 1; | 108 | state->exit_latency = 2300; |
106 | state->flags = 0; | 109 | state->target_residency = 1 * 2; |
107 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | 110 | state->power_usage = 1; |
108 | state->enter = cpuidle_sleep_enter; | 111 | state->flags = 0; |
112 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
113 | state->enter = cpuidle_sleep_enter; | ||
114 | } | ||
109 | 115 | ||
110 | dev->state_count = i; | 116 | dev->state_count = i; |
111 | 117 | ||
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c index ee3c2aaf66fb..ca029a44743c 100644 --- a/arch/sh/kernel/cpu/shmobile/pm.c +++ b/arch/sh/kernel/cpu/shmobile/pm.c | |||
@@ -15,6 +15,13 @@ | |||
15 | #include <linux/suspend.h> | 15 | #include <linux/suspend.h> |
16 | #include <asm/suspend.h> | 16 | #include <asm/suspend.h> |
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | #include <asm/cacheflush.h> | ||
19 | |||
20 | /* | ||
21 | * Notifier lists for pre/post sleep notification | ||
22 | */ | ||
23 | ATOMIC_NOTIFIER_HEAD(sh_mobile_pre_sleep_notifier_list); | ||
24 | ATOMIC_NOTIFIER_HEAD(sh_mobile_post_sleep_notifier_list); | ||
18 | 25 | ||
19 | /* | 26 | /* |
20 | * Sleep modes available on SuperH Mobile: | 27 | * Sleep modes available on SuperH Mobile: |
@@ -26,30 +33,105 @@ | |||
26 | #define SUSP_MODE_SLEEP (SUSP_SH_SLEEP) | 33 | #define SUSP_MODE_SLEEP (SUSP_SH_SLEEP) |
27 | #define SUSP_MODE_SLEEP_SF (SUSP_SH_SLEEP | SUSP_SH_SF) | 34 | #define SUSP_MODE_SLEEP_SF (SUSP_SH_SLEEP | SUSP_SH_SF) |
28 | #define SUSP_MODE_STANDBY_SF (SUSP_SH_STANDBY | SUSP_SH_SF) | 35 | #define SUSP_MODE_STANDBY_SF (SUSP_SH_STANDBY | SUSP_SH_SF) |
36 | #define SUSP_MODE_RSTANDBY (SUSP_SH_RSTANDBY | SUSP_SH_MMU | SUSP_SH_SF) | ||
37 | /* | ||
38 | * U-standby mode is unsupported since it needs bootloader hacks | ||
39 | */ | ||
29 | 40 | ||
30 | /* | 41 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 |
31 | * The following modes are not there yet: | 42 | #define RAM_BASE 0xfd800000 /* RSMEM */ |
32 | * | 43 | #else |
33 | * R-standby mode is unsupported, but will be added in the future | 44 | #define RAM_BASE 0xe5200000 /* ILRAM */ |
34 | * U-standby mode is low priority since it needs bootloader hacks | 45 | #endif |
35 | */ | ||
36 | |||
37 | #define ILRAM_BASE 0xe5200000 | ||
38 | |||
39 | extern const unsigned char sh_mobile_standby[]; | ||
40 | extern const unsigned int sh_mobile_standby_size; | ||
41 | 46 | ||
42 | void sh_mobile_call_standby(unsigned long mode) | 47 | void sh_mobile_call_standby(unsigned long mode) |
43 | { | 48 | { |
44 | void *onchip_mem = (void *)ILRAM_BASE; | 49 | void *onchip_mem = (void *)RAM_BASE; |
45 | void (*standby_onchip_mem)(unsigned long, unsigned long) = onchip_mem; | 50 | struct sh_sleep_data *sdp = onchip_mem; |
51 | void (*standby_onchip_mem)(unsigned long, unsigned long); | ||
52 | |||
53 | /* code located directly after data structure */ | ||
54 | standby_onchip_mem = (void *)(sdp + 1); | ||
55 | |||
56 | atomic_notifier_call_chain(&sh_mobile_pre_sleep_notifier_list, | ||
57 | mode, NULL); | ||
58 | |||
59 | /* flush the caches if MMU flag is set */ | ||
60 | if (mode & SUSP_SH_MMU) | ||
61 | flush_cache_all(); | ||
46 | 62 | ||
47 | /* Let assembly snippet in on-chip memory handle the rest */ | 63 | /* Let assembly snippet in on-chip memory handle the rest */ |
48 | standby_onchip_mem(mode, ILRAM_BASE); | 64 | standby_onchip_mem(mode, RAM_BASE); |
65 | |||
66 | atomic_notifier_call_chain(&sh_mobile_post_sleep_notifier_list, | ||
67 | mode, NULL); | ||
68 | } | ||
69 | |||
70 | extern char sh_mobile_sleep_enter_start; | ||
71 | extern char sh_mobile_sleep_enter_end; | ||
72 | |||
73 | extern char sh_mobile_sleep_resume_start; | ||
74 | extern char sh_mobile_sleep_resume_end; | ||
75 | |||
76 | unsigned long sh_mobile_sleep_supported = SUSP_SH_SLEEP; | ||
77 | |||
78 | void sh_mobile_register_self_refresh(unsigned long flags, | ||
79 | void *pre_start, void *pre_end, | ||
80 | void *post_start, void *post_end) | ||
81 | { | ||
82 | void *onchip_mem = (void *)RAM_BASE; | ||
83 | void *vp; | ||
84 | struct sh_sleep_data *sdp; | ||
85 | int n; | ||
86 | |||
87 | /* part 0: data area */ | ||
88 | sdp = onchip_mem; | ||
89 | sdp->addr.stbcr = 0xa4150020; /* STBCR */ | ||
90 | sdp->addr.bar = 0xa4150040; /* BAR */ | ||
91 | sdp->addr.pteh = 0xff000000; /* PTEH */ | ||
92 | sdp->addr.ptel = 0xff000004; /* PTEL */ | ||
93 | sdp->addr.ttb = 0xff000008; /* TTB */ | ||
94 | sdp->addr.tea = 0xff00000c; /* TEA */ | ||
95 | sdp->addr.mmucr = 0xff000010; /* MMUCR */ | ||
96 | sdp->addr.ptea = 0xff000034; /* PTEA */ | ||
97 | sdp->addr.pascr = 0xff000070; /* PASCR */ | ||
98 | sdp->addr.irmcr = 0xff000078; /* IRMCR */ | ||
99 | sdp->addr.ccr = 0xff00001c; /* CCR */ | ||
100 | sdp->addr.ramcr = 0xff000074; /* RAMCR */ | ||
101 | vp = sdp + 1; | ||
102 | |||
103 | /* part 1: common code to enter sleep mode */ | ||
104 | n = &sh_mobile_sleep_enter_end - &sh_mobile_sleep_enter_start; | ||
105 | memcpy(vp, &sh_mobile_sleep_enter_start, n); | ||
106 | vp += roundup(n, 4); | ||
107 | |||
108 | /* part 2: board specific code to enter self-refresh mode */ | ||
109 | n = pre_end - pre_start; | ||
110 | memcpy(vp, pre_start, n); | ||
111 | sdp->sf_pre = (unsigned long)vp; | ||
112 | vp += roundup(n, 4); | ||
113 | |||
114 | /* part 3: board specific code to resume from self-refresh mode */ | ||
115 | n = post_end - post_start; | ||
116 | memcpy(vp, post_start, n); | ||
117 | sdp->sf_post = (unsigned long)vp; | ||
118 | vp += roundup(n, 4); | ||
119 | |||
120 | /* part 4: common code to resume from sleep mode */ | ||
121 | WARN_ON(vp > (onchip_mem + 0x600)); | ||
122 | vp = onchip_mem + 0x600; /* located at interrupt vector */ | ||
123 | n = &sh_mobile_sleep_resume_end - &sh_mobile_sleep_resume_start; | ||
124 | memcpy(vp, &sh_mobile_sleep_resume_start, n); | ||
125 | sdp->resume = (unsigned long)vp; | ||
126 | |||
127 | sh_mobile_sleep_supported |= flags; | ||
49 | } | 128 | } |
50 | 129 | ||
51 | static int sh_pm_enter(suspend_state_t state) | 130 | static int sh_pm_enter(suspend_state_t state) |
52 | { | 131 | { |
132 | if (!(sh_mobile_sleep_supported & SUSP_MODE_STANDBY_SF)) | ||
133 | return -ENXIO; | ||
134 | |||
53 | local_irq_disable(); | 135 | local_irq_disable(); |
54 | set_bl_bit(); | 136 | set_bl_bit(); |
55 | sh_mobile_call_standby(SUSP_MODE_STANDBY_SF); | 137 | sh_mobile_call_standby(SUSP_MODE_STANDBY_SF); |
@@ -65,13 +147,6 @@ static struct platform_suspend_ops sh_pm_ops = { | |||
65 | 147 | ||
66 | static int __init sh_pm_init(void) | 148 | static int __init sh_pm_init(void) |
67 | { | 149 | { |
68 | void *onchip_mem = (void *)ILRAM_BASE; | ||
69 | |||
70 | /* Copy the assembly snippet to the otherwise ununsed ILRAM */ | ||
71 | memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size); | ||
72 | wmb(); | ||
73 | ctrl_barrier(); | ||
74 | |||
75 | suspend_set_ops(&sh_pm_ops); | 150 | suspend_set_ops(&sh_pm_ops); |
76 | sh_mobile_setup_cpuidle(); | 151 | sh_mobile_setup_cpuidle(); |
77 | return 0; | 152 | return 0; |
diff --git a/arch/sh/kernel/cpu/shmobile/pm_runtime.c b/arch/sh/kernel/cpu/shmobile/pm_runtime.c index 7c615b17e209..6dcb8166a64d 100644 --- a/arch/sh/kernel/cpu/shmobile/pm_runtime.c +++ b/arch/sh/kernel/cpu/shmobile/pm_runtime.c | |||
@@ -45,12 +45,14 @@ static int __platform_pm_runtime_resume(struct platform_device *pdev) | |||
45 | 45 | ||
46 | dev_dbg(d, "__platform_pm_runtime_resume() [%d]\n", hwblk); | 46 | dev_dbg(d, "__platform_pm_runtime_resume() [%d]\n", hwblk); |
47 | 47 | ||
48 | if (d->driver && d->driver->pm && d->driver->pm->runtime_resume) { | 48 | if (d->driver) { |
49 | hwblk_enable(hwblk_info, hwblk); | 49 | hwblk_enable(hwblk_info, hwblk); |
50 | ret = 0; | 50 | ret = 0; |
51 | 51 | ||
52 | if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) { | 52 | if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) { |
53 | ret = d->driver->pm->runtime_resume(d); | 53 | if (d->driver->pm && d->driver->pm->runtime_resume) |
54 | ret = d->driver->pm->runtime_resume(d); | ||
55 | |||
54 | if (!ret) | 56 | if (!ret) |
55 | clear_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); | 57 | clear_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); |
56 | else | 58 | else |
@@ -73,12 +75,15 @@ static int __platform_pm_runtime_suspend(struct platform_device *pdev) | |||
73 | 75 | ||
74 | dev_dbg(d, "__platform_pm_runtime_suspend() [%d]\n", hwblk); | 76 | dev_dbg(d, "__platform_pm_runtime_suspend() [%d]\n", hwblk); |
75 | 77 | ||
76 | if (d->driver && d->driver->pm && d->driver->pm->runtime_suspend) { | 78 | if (d->driver) { |
77 | BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags)); | 79 | BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags)); |
80 | ret = 0; | ||
78 | 81 | ||
79 | hwblk_enable(hwblk_info, hwblk); | 82 | if (d->driver->pm && d->driver->pm->runtime_suspend) { |
80 | ret = d->driver->pm->runtime_suspend(d); | 83 | hwblk_enable(hwblk_info, hwblk); |
81 | hwblk_disable(hwblk_info, hwblk); | 84 | ret = d->driver->pm->runtime_suspend(d); |
85 | hwblk_disable(hwblk_info, hwblk); | ||
86 | } | ||
82 | 87 | ||
83 | if (!ret) { | 88 | if (!ret) { |
84 | set_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); | 89 | set_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); |
diff --git a/arch/sh/kernel/cpu/shmobile/sleep.S b/arch/sh/kernel/cpu/shmobile/sleep.S index a439e6c7824f..e9dd7fa0abd2 100644 --- a/arch/sh/kernel/cpu/shmobile/sleep.S +++ b/arch/sh/kernel/cpu/shmobile/sleep.S | |||
@@ -20,79 +20,103 @@ | |||
20 | * Kernel mode register usage, see entry.S: | 20 | * Kernel mode register usage, see entry.S: |
21 | * k0 scratch | 21 | * k0 scratch |
22 | * k1 scratch | 22 | * k1 scratch |
23 | * k4 scratch | ||
24 | */ | 23 | */ |
25 | #define k0 r0 | 24 | #define k0 r0 |
26 | #define k1 r1 | 25 | #define k1 r1 |
27 | #define k4 r4 | ||
28 | 26 | ||
29 | /* manage self-refresh and enter standby mode. | 27 | /* manage self-refresh and enter standby mode. must be self-contained. |
30 | * this code will be copied to on-chip memory and executed from there. | 28 | * this code will be copied to on-chip memory and executed from there. |
31 | */ | 29 | */ |
30 | .balign 4 | ||
31 | ENTRY(sh_mobile_sleep_enter_start) | ||
32 | 32 | ||
33 | .balign 4096,0,4096 | 33 | /* save mode flags */ |
34 | ENTRY(sh_mobile_standby) | 34 | mov.l r4, @(SH_SLEEP_MODE, r5) |
35 | 35 | ||
36 | /* save original vbr */ | 36 | /* save original vbr */ |
37 | stc vbr, r1 | 37 | stc vbr, r0 |
38 | mova saved_vbr, r0 | 38 | mov.l r0, @(SH_SLEEP_VBR, r5) |
39 | mov.l r1, @r0 | ||
40 | 39 | ||
41 | /* point vbr to our on-chip memory page */ | 40 | /* point vbr to our on-chip memory page */ |
42 | ldc r5, vbr | 41 | ldc r5, vbr |
43 | 42 | ||
44 | /* save return address */ | 43 | /* save return address */ |
45 | mova saved_spc, r0 | 44 | sts pr, r0 |
46 | sts pr, r5 | 45 | mov.l r0, @(SH_SLEEP_SPC, r5) |
47 | mov.l r5, @r0 | ||
48 | 46 | ||
49 | /* save sr */ | 47 | /* save sr */ |
50 | mova saved_sr, r0 | 48 | stc sr, r0 |
51 | stc sr, r5 | 49 | mov.l r0, @(SH_SLEEP_SR, r5) |
52 | mov.l r5, @r0 | ||
53 | 50 | ||
54 | /* save mode flags */ | 51 | /* save sp */ |
55 | mova saved_mode, r0 | 52 | mov.l r15, @(SH_SLEEP_SP, r5) |
56 | mov.l r4, @r0 | 53 | |
54 | /* save stbcr */ | ||
55 | bsr save_register | ||
56 | mov #SH_SLEEP_REG_STBCR, r0 | ||
57 | |||
58 | /* save mmu and cache context if needed */ | ||
59 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
60 | tst #SUSP_SH_MMU, r0 | ||
61 | bt skip_mmu_save_disable | ||
62 | |||
63 | /* save mmu state */ | ||
64 | bsr save_register | ||
65 | mov #SH_SLEEP_REG_PTEH, r0 | ||
66 | |||
67 | bsr save_register | ||
68 | mov #SH_SLEEP_REG_PTEL, r0 | ||
69 | |||
70 | bsr save_register | ||
71 | mov #SH_SLEEP_REG_TTB, r0 | ||
72 | |||
73 | bsr save_register | ||
74 | mov #SH_SLEEP_REG_TEA, r0 | ||
75 | |||
76 | bsr save_register | ||
77 | mov #SH_SLEEP_REG_MMUCR, r0 | ||
78 | |||
79 | bsr save_register | ||
80 | mov #SH_SLEEP_REG_PTEA, r0 | ||
81 | |||
82 | bsr save_register | ||
83 | mov #SH_SLEEP_REG_PASCR, r0 | ||
57 | 84 | ||
58 | /* put mode flags in r0 */ | 85 | bsr save_register |
59 | mov r4, r0 | 86 | mov #SH_SLEEP_REG_IRMCR, r0 |
60 | 87 | ||
88 | /* invalidate TLBs and disable the MMU */ | ||
89 | bsr get_register | ||
90 | mov #SH_SLEEP_REG_MMUCR, r0 | ||
91 | mov #4, r1 | ||
92 | mov.l r1, @r0 | ||
93 | icbi @r0 | ||
94 | |||
95 | /* save cache registers and disable caches */ | ||
96 | bsr save_register | ||
97 | mov #SH_SLEEP_REG_CCR, r0 | ||
98 | |||
99 | bsr save_register | ||
100 | mov #SH_SLEEP_REG_RAMCR, r0 | ||
101 | |||
102 | bsr get_register | ||
103 | mov #SH_SLEEP_REG_CCR, r0 | ||
104 | mov #0, r1 | ||
105 | mov.l r1, @r0 | ||
106 | icbi @r0 | ||
107 | |||
108 | skip_mmu_save_disable: | ||
109 | /* call self-refresh entering code if needed */ | ||
110 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
61 | tst #SUSP_SH_SF, r0 | 111 | tst #SUSP_SH_SF, r0 |
62 | bt skip_set_sf | 112 | bt skip_set_sf |
63 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 | 113 | |
64 | /* DBSC: put memory in self-refresh mode */ | 114 | mov.l @(SH_SLEEP_SF_PRE, r5), r0 |
65 | mov.l dben_reg, r4 | 115 | jsr @r0 |
66 | mov.l dben_data0, r1 | 116 | nop |
67 | mov.l r1, @r4 | ||
68 | |||
69 | mov.l dbrfpdn0_reg, r4 | ||
70 | mov.l dbrfpdn0_data0, r1 | ||
71 | mov.l r1, @r4 | ||
72 | |||
73 | mov.l dbcmdcnt_reg, r4 | ||
74 | mov.l dbcmdcnt_data0, r1 | ||
75 | mov.l r1, @r4 | ||
76 | |||
77 | mov.l dbcmdcnt_reg, r4 | ||
78 | mov.l dbcmdcnt_data1, r1 | ||
79 | mov.l r1, @r4 | ||
80 | |||
81 | mov.l dbrfpdn0_reg, r4 | ||
82 | mov.l dbrfpdn0_data1, r1 | ||
83 | mov.l r1, @r4 | ||
84 | #else | ||
85 | /* SBSC: disable power down and put in self-refresh mode */ | ||
86 | mov.l 1f, r4 | ||
87 | mov.l 2f, r1 | ||
88 | mov.l @r4, r2 | ||
89 | or r1, r2 | ||
90 | mov.l 3f, r3 | ||
91 | and r3, r2 | ||
92 | mov.l r2, @r4 | ||
93 | #endif | ||
94 | 117 | ||
95 | skip_set_sf: | 118 | skip_set_sf: |
119 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
96 | tst #SUSP_SH_STANDBY, r0 | 120 | tst #SUSP_SH_STANDBY, r0 |
97 | bt test_rstandby | 121 | bt test_rstandby |
98 | 122 | ||
@@ -104,6 +128,12 @@ test_rstandby: | |||
104 | tst #SUSP_SH_RSTANDBY, r0 | 128 | tst #SUSP_SH_RSTANDBY, r0 |
105 | bt test_ustandby | 129 | bt test_ustandby |
106 | 130 | ||
131 | /* setup BAR register */ | ||
132 | bsr get_register | ||
133 | mov #SH_SLEEP_REG_BAR, r0 | ||
134 | mov.l @(SH_SLEEP_RESUME, r5), r1 | ||
135 | mov.l r1, @r0 | ||
136 | |||
107 | /* set mode to "r-standby mode" */ | 137 | /* set mode to "r-standby mode" */ |
108 | bra do_sleep | 138 | bra do_sleep |
109 | mov #0x20, r1 | 139 | mov #0x20, r1 |
@@ -123,124 +153,136 @@ force_sleep: | |||
123 | 153 | ||
124 | do_sleep: | 154 | do_sleep: |
125 | /* setup and enter selected standby mode */ | 155 | /* setup and enter selected standby mode */ |
126 | mov.l 5f, r4 | 156 | bsr get_register |
127 | mov.l r1, @r4 | 157 | mov #SH_SLEEP_REG_STBCR, r0 |
158 | mov.l r1, @r0 | ||
128 | again: | 159 | again: |
129 | sleep | 160 | sleep |
130 | bra again | 161 | bra again |
131 | nop | 162 | nop |
132 | 163 | ||
133 | restore_jump_vbr: | 164 | save_register: |
165 | add #SH_SLEEP_BASE_ADDR, r0 | ||
166 | mov.l @(r0, r5), r1 | ||
167 | add #-SH_SLEEP_BASE_ADDR, r0 | ||
168 | mov.l @r1, r1 | ||
169 | add #SH_SLEEP_BASE_DATA, r0 | ||
170 | mov.l r1, @(r0, r5) | ||
171 | add #-SH_SLEEP_BASE_DATA, r0 | ||
172 | rts | ||
173 | nop | ||
174 | |||
175 | get_register: | ||
176 | add #SH_SLEEP_BASE_ADDR, r0 | ||
177 | mov.l @(r0, r5), r0 | ||
178 | rts | ||
179 | nop | ||
180 | ENTRY(sh_mobile_sleep_enter_end) | ||
181 | |||
182 | .balign 4 | ||
183 | ENTRY(sh_mobile_sleep_resume_start) | ||
184 | |||
185 | /* figure out start address */ | ||
186 | bsr 0f | ||
187 | nop | ||
188 | 0: | ||
189 | sts pr, k1 | ||
190 | mov.l 1f, k0 | ||
191 | and k0, k1 | ||
192 | |||
193 | /* store pointer to data area in VBR */ | ||
194 | ldc k1, vbr | ||
195 | |||
196 | /* setup sr with saved sr */ | ||
197 | mov.l @(SH_SLEEP_SR, k1), k0 | ||
198 | ldc k0, sr | ||
199 | |||
200 | /* now: user register set! */ | ||
201 | stc vbr, r5 | ||
202 | |||
134 | /* setup spc with return address to c code */ | 203 | /* setup spc with return address to c code */ |
135 | mov.l saved_spc, k0 | 204 | mov.l @(SH_SLEEP_SPC, r5), r0 |
136 | ldc k0, spc | 205 | ldc r0, spc |
137 | 206 | ||
138 | /* restore vbr */ | 207 | /* restore vbr */ |
139 | mov.l saved_vbr, k0 | 208 | mov.l @(SH_SLEEP_VBR, r5), r0 |
140 | ldc k0, vbr | 209 | ldc r0, vbr |
141 | 210 | ||
142 | /* setup ssr with saved sr */ | 211 | /* setup ssr with saved sr */ |
143 | mov.l saved_sr, k0 | 212 | mov.l @(SH_SLEEP_SR, r5), r0 |
144 | ldc k0, ssr | 213 | ldc r0, ssr |
145 | 214 | ||
146 | /* get mode flags */ | 215 | /* restore sp */ |
147 | mov.l saved_mode, k0 | 216 | mov.l @(SH_SLEEP_SP, r5), r15 |
148 | 217 | ||
149 | done_sleep: | 218 | /* restore sleep mode register */ |
150 | /* reset standby mode to sleep mode */ | 219 | bsr restore_register |
151 | mov.l 5f, k4 | 220 | mov #SH_SLEEP_REG_STBCR, r0 |
152 | mov #0x00, k1 | ||
153 | mov.l k1, @k4 | ||
154 | 221 | ||
155 | tst #SUSP_SH_SF, k0 | 222 | /* call self-refresh resume code if needed */ |
223 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
224 | tst #SUSP_SH_SF, r0 | ||
156 | bt skip_restore_sf | 225 | bt skip_restore_sf |
157 | 226 | ||
158 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 | 227 | mov.l @(SH_SLEEP_SF_POST, r5), r0 |
159 | /* DBSC: put memory in auto-refresh mode */ | 228 | jsr @r0 |
160 | mov.l dbrfpdn0_reg, k4 | 229 | nop |
161 | mov.l dbrfpdn0_data0, k1 | 230 | |
162 | mov.l k1, @k4 | ||
163 | |||
164 | nop /* sleep 140 ns */ | ||
165 | nop | ||
166 | nop | ||
167 | nop | ||
168 | |||
169 | mov.l dbcmdcnt_reg, k4 | ||
170 | mov.l dbcmdcnt_data0, k1 | ||
171 | mov.l k1, @k4 | ||
172 | |||
173 | mov.l dbcmdcnt_reg, k4 | ||
174 | mov.l dbcmdcnt_data1, k1 | ||
175 | mov.l k1, @k4 | ||
176 | |||
177 | mov.l dben_reg, k4 | ||
178 | mov.l dben_data1, k1 | ||
179 | mov.l k1, @k4 | ||
180 | |||
181 | mov.l dbrfpdn0_reg, k4 | ||
182 | mov.l dbrfpdn0_data2, k1 | ||
183 | mov.l k1, @k4 | ||
184 | #else | ||
185 | /* SBSC: set auto-refresh mode */ | ||
186 | mov.l 1f, k4 | ||
187 | mov.l @k4, k0 | ||
188 | mov.l 4f, k1 | ||
189 | and k1, k0 | ||
190 | mov.l k0, @k4 | ||
191 | mov.l 6f, k4 | ||
192 | mov.l 8f, k0 | ||
193 | mov.l @k4, k1 | ||
194 | mov #-1, k4 | ||
195 | add k4, k1 | ||
196 | or k1, k0 | ||
197 | mov.l 7f, k1 | ||
198 | mov.l k0, @k1 | ||
199 | #endif | ||
200 | skip_restore_sf: | 231 | skip_restore_sf: |
201 | /* jump to vbr vector */ | 232 | /* restore mmu and cache state if needed */ |
202 | mov.l saved_vbr, k0 | 233 | mov.l @(SH_SLEEP_MODE, r5), r0 |
203 | mov.l offset_vbr, k4 | 234 | tst #SUSP_SH_MMU, r0 |
204 | add k4, k0 | 235 | bt skip_restore_mmu |
205 | jmp @k0 | 236 | |
237 | /* restore mmu state */ | ||
238 | bsr restore_register | ||
239 | mov #SH_SLEEP_REG_PTEH, r0 | ||
240 | |||
241 | bsr restore_register | ||
242 | mov #SH_SLEEP_REG_PTEL, r0 | ||
243 | |||
244 | bsr restore_register | ||
245 | mov #SH_SLEEP_REG_TTB, r0 | ||
246 | |||
247 | bsr restore_register | ||
248 | mov #SH_SLEEP_REG_TEA, r0 | ||
249 | |||
250 | bsr restore_register | ||
251 | mov #SH_SLEEP_REG_PTEA, r0 | ||
252 | |||
253 | bsr restore_register | ||
254 | mov #SH_SLEEP_REG_PASCR, r0 | ||
255 | |||
256 | bsr restore_register | ||
257 | mov #SH_SLEEP_REG_IRMCR, r0 | ||
258 | |||
259 | bsr restore_register | ||
260 | mov #SH_SLEEP_REG_MMUCR, r0 | ||
261 | icbi @r0 | ||
262 | |||
263 | /* restore cache settings */ | ||
264 | bsr restore_register | ||
265 | mov #SH_SLEEP_REG_RAMCR, r0 | ||
266 | icbi @r0 | ||
267 | |||
268 | bsr restore_register | ||
269 | mov #SH_SLEEP_REG_CCR, r0 | ||
270 | icbi @r0 | ||
271 | |||
272 | skip_restore_mmu: | ||
273 | rte | ||
206 | nop | 274 | nop |
207 | 275 | ||
208 | .balign 4 | 276 | restore_register: |
209 | saved_mode: .long 0 | 277 | add #SH_SLEEP_BASE_DATA, r0 |
210 | saved_spc: .long 0 | 278 | mov.l @(r0, r5), r1 |
211 | saved_sr: .long 0 | 279 | add #-SH_SLEEP_BASE_DATA, r0 |
212 | saved_vbr: .long 0 | 280 | add #SH_SLEEP_BASE_ADDR, r0 |
213 | offset_vbr: .long 0x600 | 281 | mov.l @(r0, r5), r0 |
214 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 | 282 | mov.l r1, @r0 |
215 | dben_reg: .long 0xfd000010 /* DBEN */ | 283 | rts |
216 | dben_data0: .long 0 | ||
217 | dben_data1: .long 1 | ||
218 | dbrfpdn0_reg: .long 0xfd000040 /* DBRFPDN0 */ | ||
219 | dbrfpdn0_data0: .long 0 | ||
220 | dbrfpdn0_data1: .long 1 | ||
221 | dbrfpdn0_data2: .long 0x00010000 | ||
222 | dbcmdcnt_reg: .long 0xfd000014 /* DBCMDCNT */ | ||
223 | dbcmdcnt_data0: .long 2 | ||
224 | dbcmdcnt_data1: .long 4 | ||
225 | #else | ||
226 | 1: .long 0xfe400008 /* SDCR0 */ | ||
227 | 2: .long 0x00000400 | ||
228 | 3: .long 0xffff7fff | ||
229 | 4: .long 0xfffffbff | ||
230 | #endif | ||
231 | 5: .long 0xa4150020 /* STBCR */ | ||
232 | 6: .long 0xfe40001c /* RTCOR */ | ||
233 | 7: .long 0xfe400018 /* RTCNT */ | ||
234 | 8: .long 0xa55a0000 | ||
235 | |||
236 | |||
237 | /* interrupt vector @ 0x600 */ | ||
238 | .balign 0x400,0,0x400 | ||
239 | .long 0xdeadbeef | ||
240 | .balign 0x200,0,0x200 | ||
241 | bra restore_jump_vbr | ||
242 | nop | 284 | nop |
243 | sh_mobile_standby_end: | ||
244 | 285 | ||
245 | ENTRY(sh_mobile_standby_size) | 286 | .balign 4 |
246 | .long sh_mobile_standby_end - sh_mobile_standby | 287 | 1: .long ~0x7ff |
288 | ENTRY(sh_mobile_sleep_resume_end) | ||
diff --git a/arch/sh/kernel/cpu/ubc.S b/arch/sh/kernel/cpu/ubc.S deleted file mode 100644 index 81923079fa12..000000000000 --- a/arch/sh/kernel/cpu/ubc.S +++ /dev/null | |||
@@ -1,59 +0,0 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/ubc.S | ||
3 | * | ||
4 | * Set of management routines for the User Break Controller (UBC) | ||
5 | * | ||
6 | * Copyright (C) 2002 Paul Mundt | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/ubc.h> | ||
15 | |||
16 | #define STBCR2 0xffc00010 | ||
17 | |||
18 | ENTRY(ubc_sleep) | ||
19 | mov #0, r0 | ||
20 | |||
21 | mov.l 1f, r1 ! Zero out UBC_BBRA .. | ||
22 | mov.w r0, @r1 | ||
23 | |||
24 | mov.l 2f, r1 ! .. same for BBRB .. | ||
25 | mov.w r0, @r1 | ||
26 | |||
27 | mov.l 3f, r1 ! .. and again for BRCR. | ||
28 | mov.w r0, @r1 | ||
29 | |||
30 | mov.w @r1, r0 ! Dummy read BRCR | ||
31 | |||
32 | mov.l 4f, r1 ! Set MSTP5 in STBCR2 | ||
33 | mov.b @r1, r0 | ||
34 | or #0x01, r0 | ||
35 | mov.b r0, @r1 | ||
36 | |||
37 | mov.b @r1, r0 ! Two dummy reads .. | ||
38 | mov.b @r1, r0 | ||
39 | |||
40 | rts | ||
41 | nop | ||
42 | |||
43 | ENTRY(ubc_wakeup) | ||
44 | mov.l 4f, r1 ! Clear MSTP5 | ||
45 | mov.b @r1, r0 | ||
46 | and #0xfe, r0 | ||
47 | mov.b r0, @r1 | ||
48 | |||
49 | mov.b @r1, r0 ! Two more dummy reads .. | ||
50 | mov.b @r1, r0 | ||
51 | |||
52 | rts | ||
53 | nop | ||
54 | |||
55 | 1: .long UBC_BBRA | ||
56 | 2: .long UBC_BBRB | ||
57 | 3: .long UBC_BRCR | ||
58 | 4: .long STBCR2 | ||
59 | |||
diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c new file mode 100644 index 000000000000..3c55b87f8b63 --- /dev/null +++ b/arch/sh/kernel/dma-nommu.c | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * DMA mapping support for platforms lacking IOMMUs. | ||
3 | * | ||
4 | * Copyright (C) 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/dma-mapping.h> | ||
11 | #include <linux/io.h> | ||
12 | |||
13 | static dma_addr_t nommu_map_page(struct device *dev, struct page *page, | ||
14 | unsigned long offset, size_t size, | ||
15 | enum dma_data_direction dir, | ||
16 | struct dma_attrs *attrs) | ||
17 | { | ||
18 | dma_addr_t addr = page_to_phys(page) + offset; | ||
19 | |||
20 | WARN_ON(size == 0); | ||
21 | dma_cache_sync(dev, page_address(page) + offset, size, dir); | ||
22 | |||
23 | return addr; | ||
24 | } | ||
25 | |||
26 | static int nommu_map_sg(struct device *dev, struct scatterlist *sg, | ||
27 | int nents, enum dma_data_direction dir, | ||
28 | struct dma_attrs *attrs) | ||
29 | { | ||
30 | struct scatterlist *s; | ||
31 | int i; | ||
32 | |||
33 | WARN_ON(nents == 0 || sg[0].length == 0); | ||
34 | |||
35 | for_each_sg(sg, s, nents, i) { | ||
36 | BUG_ON(!sg_page(s)); | ||
37 | |||
38 | dma_cache_sync(dev, sg_virt(s), s->length, dir); | ||
39 | |||
40 | s->dma_address = sg_phys(s); | ||
41 | s->dma_length = s->length; | ||
42 | } | ||
43 | |||
44 | return nents; | ||
45 | } | ||
46 | |||
47 | #ifdef CONFIG_DMA_NONCOHERENT | ||
48 | static void nommu_sync_single(struct device *dev, dma_addr_t addr, | ||
49 | size_t size, enum dma_data_direction dir) | ||
50 | { | ||
51 | dma_cache_sync(dev, phys_to_virt(addr), size, dir); | ||
52 | } | ||
53 | |||
54 | static void nommu_sync_sg(struct device *dev, struct scatterlist *sg, | ||
55 | int nelems, enum dma_data_direction dir) | ||
56 | { | ||
57 | struct scatterlist *s; | ||
58 | int i; | ||
59 | |||
60 | for_each_sg(sg, s, nelems, i) | ||
61 | dma_cache_sync(dev, sg_virt(s), s->length, dir); | ||
62 | } | ||
63 | #endif | ||
64 | |||
65 | struct dma_map_ops nommu_dma_ops = { | ||
66 | .alloc_coherent = dma_generic_alloc_coherent, | ||
67 | .free_coherent = dma_generic_free_coherent, | ||
68 | .map_page = nommu_map_page, | ||
69 | .map_sg = nommu_map_sg, | ||
70 | #ifdef CONFIG_DMA_NONCOHERENT | ||
71 | .sync_single_for_device = nommu_sync_single, | ||
72 | .sync_sg_for_device = nommu_sync_sg, | ||
73 | #endif | ||
74 | .is_phys = 1, | ||
75 | }; | ||
76 | |||
77 | void __init no_iommu_init(void) | ||
78 | { | ||
79 | if (dma_ops) | ||
80 | return; | ||
81 | dma_ops = &nommu_dma_ops; | ||
82 | } | ||
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index d76a23170dbb..3576b709f052 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/list.h> | 20 | #include <linux/list.h> |
21 | #include <linux/mempool.h> | 21 | #include <linux/mempool.h> |
22 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
23 | #include <linux/elf.h> | ||
23 | #include <linux/ftrace.h> | 24 | #include <linux/ftrace.h> |
24 | #include <asm/dwarf.h> | 25 | #include <asm/dwarf.h> |
25 | #include <asm/unwinder.h> | 26 | #include <asm/unwinder.h> |
@@ -530,7 +531,18 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start, | |||
530 | } | 531 | } |
531 | 532 | ||
532 | /** | 533 | /** |
533 | * dwarf_unwind_stack - recursively unwind the stack | 534 | * dwarf_free_frame - free the memory allocated for @frame |
535 | * @frame: the frame to free | ||
536 | */ | ||
537 | void dwarf_free_frame(struct dwarf_frame *frame) | ||
538 | { | ||
539 | dwarf_frame_free_regs(frame); | ||
540 | mempool_free(frame, dwarf_frame_pool); | ||
541 | } | ||
542 | |||
543 | /** | ||
544 | * dwarf_unwind_stack - unwind the stack | ||
545 | * | ||
534 | * @pc: address of the function to unwind | 546 | * @pc: address of the function to unwind |
535 | * @prev: struct dwarf_frame of the previous stackframe on the callstack | 547 | * @prev: struct dwarf_frame of the previous stackframe on the callstack |
536 | * | 548 | * |
@@ -548,9 +560,9 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc, | |||
548 | unsigned long addr; | 560 | unsigned long addr; |
549 | 561 | ||
550 | /* | 562 | /* |
551 | * If this is the first invocation of this recursive function we | 563 | * If we're starting at the top of the stack we need get the |
552 | * need get the contents of a physical register to get the CFA | 564 | * contents of a physical register to get the CFA in order to |
553 | * in order to begin the virtual unwinding of the stack. | 565 | * begin the virtual unwinding of the stack. |
554 | * | 566 | * |
555 | * NOTE: the return address is guaranteed to be setup by the | 567 | * NOTE: the return address is guaranteed to be setup by the |
556 | * time this function makes its first function call. | 568 | * time this function makes its first function call. |
@@ -593,9 +605,8 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc, | |||
593 | fde = dwarf_lookup_fde(pc); | 605 | fde = dwarf_lookup_fde(pc); |
594 | if (!fde) { | 606 | if (!fde) { |
595 | /* | 607 | /* |
596 | * This is our normal exit path - the one that stops the | 608 | * This is our normal exit path. There are two reasons |
597 | * recursion. There's two reasons why we might exit | 609 | * why we might exit here, |
598 | * here, | ||
599 | * | 610 | * |
600 | * a) pc has no asscociated DWARF frame info and so | 611 | * a) pc has no asscociated DWARF frame info and so |
601 | * we don't know how to unwind this frame. This is | 612 | * we don't know how to unwind this frame. This is |
@@ -637,10 +648,10 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc, | |||
637 | 648 | ||
638 | } else { | 649 | } else { |
639 | /* | 650 | /* |
640 | * Again, this is the first invocation of this | 651 | * Again, we're starting from the top of the |
641 | * recurisve function. We need to physically | 652 | * stack. We need to physically read |
642 | * read the contents of a register in order to | 653 | * the contents of a register in order to get |
643 | * get the Canonical Frame Address for this | 654 | * the Canonical Frame Address for this |
644 | * function. | 655 | * function. |
645 | */ | 656 | */ |
646 | frame->cfa = dwarf_read_arch_reg(frame->cfa_register); | 657 | frame->cfa = dwarf_read_arch_reg(frame->cfa_register); |
@@ -670,13 +681,12 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc, | |||
670 | return frame; | 681 | return frame; |
671 | 682 | ||
672 | bail: | 683 | bail: |
673 | dwarf_frame_free_regs(frame); | 684 | dwarf_free_frame(frame); |
674 | mempool_free(frame, dwarf_frame_pool); | ||
675 | return NULL; | 685 | return NULL; |
676 | } | 686 | } |
677 | 687 | ||
678 | static int dwarf_parse_cie(void *entry, void *p, unsigned long len, | 688 | static int dwarf_parse_cie(void *entry, void *p, unsigned long len, |
679 | unsigned char *end) | 689 | unsigned char *end, struct module *mod) |
680 | { | 690 | { |
681 | struct dwarf_cie *cie; | 691 | struct dwarf_cie *cie; |
682 | unsigned long flags; | 692 | unsigned long flags; |
@@ -772,6 +782,8 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len, | |||
772 | cie->initial_instructions = p; | 782 | cie->initial_instructions = p; |
773 | cie->instructions_end = end; | 783 | cie->instructions_end = end; |
774 | 784 | ||
785 | cie->mod = mod; | ||
786 | |||
775 | /* Add to list */ | 787 | /* Add to list */ |
776 | spin_lock_irqsave(&dwarf_cie_lock, flags); | 788 | spin_lock_irqsave(&dwarf_cie_lock, flags); |
777 | list_add_tail(&cie->link, &dwarf_cie_list); | 789 | list_add_tail(&cie->link, &dwarf_cie_list); |
@@ -782,7 +794,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len, | |||
782 | 794 | ||
783 | static int dwarf_parse_fde(void *entry, u32 entry_type, | 795 | static int dwarf_parse_fde(void *entry, u32 entry_type, |
784 | void *start, unsigned long len, | 796 | void *start, unsigned long len, |
785 | unsigned char *end) | 797 | unsigned char *end, struct module *mod) |
786 | { | 798 | { |
787 | struct dwarf_fde *fde; | 799 | struct dwarf_fde *fde; |
788 | struct dwarf_cie *cie; | 800 | struct dwarf_cie *cie; |
@@ -831,6 +843,8 @@ static int dwarf_parse_fde(void *entry, u32 entry_type, | |||
831 | fde->instructions = p; | 843 | fde->instructions = p; |
832 | fde->end = end; | 844 | fde->end = end; |
833 | 845 | ||
846 | fde->mod = mod; | ||
847 | |||
834 | /* Add to list. */ | 848 | /* Add to list. */ |
835 | spin_lock_irqsave(&dwarf_fde_lock, flags); | 849 | spin_lock_irqsave(&dwarf_fde_lock, flags); |
836 | list_add_tail(&fde->link, &dwarf_fde_list); | 850 | list_add_tail(&fde->link, &dwarf_fde_list); |
@@ -854,10 +868,8 @@ static void dwarf_unwinder_dump(struct task_struct *task, | |||
854 | while (1) { | 868 | while (1) { |
855 | frame = dwarf_unwind_stack(return_addr, _frame); | 869 | frame = dwarf_unwind_stack(return_addr, _frame); |
856 | 870 | ||
857 | if (_frame) { | 871 | if (_frame) |
858 | dwarf_frame_free_regs(_frame); | 872 | dwarf_free_frame(_frame); |
859 | mempool_free(_frame, dwarf_frame_pool); | ||
860 | } | ||
861 | 873 | ||
862 | _frame = frame; | 874 | _frame = frame; |
863 | 875 | ||
@@ -867,6 +879,9 @@ static void dwarf_unwinder_dump(struct task_struct *task, | |||
867 | return_addr = frame->return_addr; | 879 | return_addr = frame->return_addr; |
868 | ops->address(data, return_addr, 1); | 880 | ops->address(data, return_addr, 1); |
869 | } | 881 | } |
882 | |||
883 | if (frame) | ||
884 | dwarf_free_frame(frame); | ||
870 | } | 885 | } |
871 | 886 | ||
872 | static struct unwinder dwarf_unwinder = { | 887 | static struct unwinder dwarf_unwinder = { |
@@ -896,48 +911,28 @@ static void dwarf_unwinder_cleanup(void) | |||
896 | } | 911 | } |
897 | 912 | ||
898 | /** | 913 | /** |
899 | * dwarf_unwinder_init - initialise the dwarf unwinder | 914 | * dwarf_parse_section - parse DWARF section |
915 | * @eh_frame_start: start address of the .eh_frame section | ||
916 | * @eh_frame_end: end address of the .eh_frame section | ||
917 | * @mod: the kernel module containing the .eh_frame section | ||
900 | * | 918 | * |
901 | * Build the data structures describing the .dwarf_frame section to | 919 | * Parse the information in a .eh_frame section. |
902 | * make it easier to lookup CIE and FDE entries. Because the | ||
903 | * .eh_frame section is packed as tightly as possible it is not | ||
904 | * easy to lookup the FDE for a given PC, so we build a list of FDE | ||
905 | * and CIE entries that make it easier. | ||
906 | */ | 920 | */ |
907 | static int __init dwarf_unwinder_init(void) | 921 | static int dwarf_parse_section(char *eh_frame_start, char *eh_frame_end, |
922 | struct module *mod) | ||
908 | { | 923 | { |
909 | u32 entry_type; | 924 | u32 entry_type; |
910 | void *p, *entry; | 925 | void *p, *entry; |
911 | int count, err = 0; | 926 | int count, err = 0; |
912 | unsigned long len; | 927 | unsigned long len = 0; |
913 | unsigned int c_entries, f_entries; | 928 | unsigned int c_entries, f_entries; |
914 | unsigned char *end; | 929 | unsigned char *end; |
915 | INIT_LIST_HEAD(&dwarf_cie_list); | ||
916 | INIT_LIST_HEAD(&dwarf_fde_list); | ||
917 | 930 | ||
918 | c_entries = 0; | 931 | c_entries = 0; |
919 | f_entries = 0; | 932 | f_entries = 0; |
920 | entry = &__start_eh_frame; | 933 | entry = eh_frame_start; |
921 | |||
922 | dwarf_frame_cachep = kmem_cache_create("dwarf_frames", | ||
923 | sizeof(struct dwarf_frame), 0, | ||
924 | SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL); | ||
925 | |||
926 | dwarf_reg_cachep = kmem_cache_create("dwarf_regs", | ||
927 | sizeof(struct dwarf_reg), 0, | ||
928 | SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL); | ||
929 | 934 | ||
930 | dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ, | 935 | while ((char *)entry < eh_frame_end) { |
931 | mempool_alloc_slab, | ||
932 | mempool_free_slab, | ||
933 | dwarf_frame_cachep); | ||
934 | |||
935 | dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ, | ||
936 | mempool_alloc_slab, | ||
937 | mempool_free_slab, | ||
938 | dwarf_reg_cachep); | ||
939 | |||
940 | while ((char *)entry < __stop_eh_frame) { | ||
941 | p = entry; | 936 | p = entry; |
942 | 937 | ||
943 | count = dwarf_entry_len(p, &len); | 938 | count = dwarf_entry_len(p, &len); |
@@ -949,6 +944,7 @@ static int __init dwarf_unwinder_init(void) | |||
949 | * entry and move to the next one because 'len' | 944 | * entry and move to the next one because 'len' |
950 | * tells us where our next entry is. | 945 | * tells us where our next entry is. |
951 | */ | 946 | */ |
947 | err = -EINVAL; | ||
952 | goto out; | 948 | goto out; |
953 | } else | 949 | } else |
954 | p += count; | 950 | p += count; |
@@ -960,13 +956,14 @@ static int __init dwarf_unwinder_init(void) | |||
960 | p += 4; | 956 | p += 4; |
961 | 957 | ||
962 | if (entry_type == DW_EH_FRAME_CIE) { | 958 | if (entry_type == DW_EH_FRAME_CIE) { |
963 | err = dwarf_parse_cie(entry, p, len, end); | 959 | err = dwarf_parse_cie(entry, p, len, end, mod); |
964 | if (err < 0) | 960 | if (err < 0) |
965 | goto out; | 961 | goto out; |
966 | else | 962 | else |
967 | c_entries++; | 963 | c_entries++; |
968 | } else { | 964 | } else { |
969 | err = dwarf_parse_fde(entry, entry_type, p, len, end); | 965 | err = dwarf_parse_fde(entry, entry_type, p, len, |
966 | end, mod); | ||
970 | if (err < 0) | 967 | if (err < 0) |
971 | goto out; | 968 | goto out; |
972 | else | 969 | else |
@@ -979,6 +976,129 @@ static int __init dwarf_unwinder_init(void) | |||
979 | printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n", | 976 | printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n", |
980 | c_entries, f_entries); | 977 | c_entries, f_entries); |
981 | 978 | ||
979 | return 0; | ||
980 | |||
981 | out: | ||
982 | return err; | ||
983 | } | ||
984 | |||
985 | #ifdef CONFIG_MODULES | ||
986 | int module_dwarf_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, | ||
987 | struct module *me) | ||
988 | { | ||
989 | unsigned int i, err; | ||
990 | unsigned long start, end; | ||
991 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
992 | |||
993 | start = end = 0; | ||
994 | |||
995 | for (i = 1; i < hdr->e_shnum; i++) { | ||
996 | /* Alloc bit cleared means "ignore it." */ | ||
997 | if ((sechdrs[i].sh_flags & SHF_ALLOC) | ||
998 | && !strcmp(secstrings+sechdrs[i].sh_name, ".eh_frame")) { | ||
999 | start = sechdrs[i].sh_addr; | ||
1000 | end = start + sechdrs[i].sh_size; | ||
1001 | break; | ||
1002 | } | ||
1003 | } | ||
1004 | |||
1005 | /* Did we find the .eh_frame section? */ | ||
1006 | if (i != hdr->e_shnum) { | ||
1007 | err = dwarf_parse_section((char *)start, (char *)end, me); | ||
1008 | if (err) { | ||
1009 | printk(KERN_WARNING "%s: failed to parse DWARF info\n", | ||
1010 | me->name); | ||
1011 | return err; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | /** | ||
1019 | * module_dwarf_cleanup - remove FDE/CIEs associated with @mod | ||
1020 | * @mod: the module that is being unloaded | ||
1021 | * | ||
1022 | * Remove any FDEs and CIEs from the global lists that came from | ||
1023 | * @mod's .eh_frame section because @mod is being unloaded. | ||
1024 | */ | ||
1025 | void module_dwarf_cleanup(struct module *mod) | ||
1026 | { | ||
1027 | struct dwarf_fde *fde; | ||
1028 | struct dwarf_cie *cie; | ||
1029 | unsigned long flags; | ||
1030 | |||
1031 | spin_lock_irqsave(&dwarf_cie_lock, flags); | ||
1032 | |||
1033 | again_cie: | ||
1034 | list_for_each_entry(cie, &dwarf_cie_list, link) { | ||
1035 | if (cie->mod == mod) | ||
1036 | break; | ||
1037 | } | ||
1038 | |||
1039 | if (&cie->link != &dwarf_cie_list) { | ||
1040 | list_del(&cie->link); | ||
1041 | kfree(cie); | ||
1042 | goto again_cie; | ||
1043 | } | ||
1044 | |||
1045 | spin_unlock_irqrestore(&dwarf_cie_lock, flags); | ||
1046 | |||
1047 | spin_lock_irqsave(&dwarf_fde_lock, flags); | ||
1048 | |||
1049 | again_fde: | ||
1050 | list_for_each_entry(fde, &dwarf_fde_list, link) { | ||
1051 | if (fde->mod == mod) | ||
1052 | break; | ||
1053 | } | ||
1054 | |||
1055 | if (&fde->link != &dwarf_fde_list) { | ||
1056 | list_del(&fde->link); | ||
1057 | kfree(fde); | ||
1058 | goto again_fde; | ||
1059 | } | ||
1060 | |||
1061 | spin_unlock_irqrestore(&dwarf_fde_lock, flags); | ||
1062 | } | ||
1063 | #endif /* CONFIG_MODULES */ | ||
1064 | |||
1065 | /** | ||
1066 | * dwarf_unwinder_init - initialise the dwarf unwinder | ||
1067 | * | ||
1068 | * Build the data structures describing the .dwarf_frame section to | ||
1069 | * make it easier to lookup CIE and FDE entries. Because the | ||
1070 | * .eh_frame section is packed as tightly as possible it is not | ||
1071 | * easy to lookup the FDE for a given PC, so we build a list of FDE | ||
1072 | * and CIE entries that make it easier. | ||
1073 | */ | ||
1074 | static int __init dwarf_unwinder_init(void) | ||
1075 | { | ||
1076 | int err; | ||
1077 | INIT_LIST_HEAD(&dwarf_cie_list); | ||
1078 | INIT_LIST_HEAD(&dwarf_fde_list); | ||
1079 | |||
1080 | dwarf_frame_cachep = kmem_cache_create("dwarf_frames", | ||
1081 | sizeof(struct dwarf_frame), 0, | ||
1082 | SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL); | ||
1083 | |||
1084 | dwarf_reg_cachep = kmem_cache_create("dwarf_regs", | ||
1085 | sizeof(struct dwarf_reg), 0, | ||
1086 | SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL); | ||
1087 | |||
1088 | dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ, | ||
1089 | mempool_alloc_slab, | ||
1090 | mempool_free_slab, | ||
1091 | dwarf_frame_cachep); | ||
1092 | |||
1093 | dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ, | ||
1094 | mempool_alloc_slab, | ||
1095 | mempool_free_slab, | ||
1096 | dwarf_reg_cachep); | ||
1097 | |||
1098 | err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL); | ||
1099 | if (err) | ||
1100 | goto out; | ||
1101 | |||
982 | err = unwinder_register(&dwarf_unwinder); | 1102 | err = unwinder_register(&dwarf_unwinder); |
983 | if (err) | 1103 | if (err) |
984 | goto out; | 1104 | goto out; |
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index 3eb84931d2aa..f0abd58c3a69 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S | |||
@@ -133,7 +133,7 @@ work_pending: | |||
133 | ! r8: current_thread_info | 133 | ! r8: current_thread_info |
134 | ! t: result of "tst #_TIF_NEED_RESCHED, r0" | 134 | ! t: result of "tst #_TIF_NEED_RESCHED, r0" |
135 | bf/s work_resched | 135 | bf/s work_resched |
136 | tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0 | 136 | tst #_TIF_SIGPENDING, r0 |
137 | work_notifysig: | 137 | work_notifysig: |
138 | bt/s __restore_all | 138 | bt/s __restore_all |
139 | mov r15, r4 | 139 | mov r15, r4 |
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c index 2c48e267256e..b6f41c109beb 100644 --- a/arch/sh/kernel/ftrace.c +++ b/arch/sh/kernel/ftrace.c | |||
@@ -62,6 +62,150 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | |||
62 | return ftrace_replaced_code; | 62 | return ftrace_replaced_code; |
63 | } | 63 | } |
64 | 64 | ||
65 | /* | ||
66 | * Modifying code must take extra care. On an SMP machine, if | ||
67 | * the code being modified is also being executed on another CPU | ||
68 | * that CPU will have undefined results and possibly take a GPF. | ||
69 | * We use kstop_machine to stop other CPUS from exectuing code. | ||
70 | * But this does not stop NMIs from happening. We still need | ||
71 | * to protect against that. We separate out the modification of | ||
72 | * the code to take care of this. | ||
73 | * | ||
74 | * Two buffers are added: An IP buffer and a "code" buffer. | ||
75 | * | ||
76 | * 1) Put the instruction pointer into the IP buffer | ||
77 | * and the new code into the "code" buffer. | ||
78 | * 2) Wait for any running NMIs to finish and set a flag that says | ||
79 | * we are modifying code, it is done in an atomic operation. | ||
80 | * 3) Write the code | ||
81 | * 4) clear the flag. | ||
82 | * 5) Wait for any running NMIs to finish. | ||
83 | * | ||
84 | * If an NMI is executed, the first thing it does is to call | ||
85 | * "ftrace_nmi_enter". This will check if the flag is set to write | ||
86 | * and if it is, it will write what is in the IP and "code" buffers. | ||
87 | * | ||
88 | * The trick is, it does not matter if everyone is writing the same | ||
89 | * content to the code location. Also, if a CPU is executing code | ||
90 | * it is OK to write to that code location if the contents being written | ||
91 | * are the same as what exists. | ||
92 | */ | ||
93 | #define MOD_CODE_WRITE_FLAG (1 << 31) /* set when NMI should do the write */ | ||
94 | static atomic_t nmi_running = ATOMIC_INIT(0); | ||
95 | static int mod_code_status; /* holds return value of text write */ | ||
96 | static void *mod_code_ip; /* holds the IP to write to */ | ||
97 | static void *mod_code_newcode; /* holds the text to write to the IP */ | ||
98 | |||
99 | static unsigned nmi_wait_count; | ||
100 | static atomic_t nmi_update_count = ATOMIC_INIT(0); | ||
101 | |||
102 | int ftrace_arch_read_dyn_info(char *buf, int size) | ||
103 | { | ||
104 | int r; | ||
105 | |||
106 | r = snprintf(buf, size, "%u %u", | ||
107 | nmi_wait_count, | ||
108 | atomic_read(&nmi_update_count)); | ||
109 | return r; | ||
110 | } | ||
111 | |||
112 | static void clear_mod_flag(void) | ||
113 | { | ||
114 | int old = atomic_read(&nmi_running); | ||
115 | |||
116 | for (;;) { | ||
117 | int new = old & ~MOD_CODE_WRITE_FLAG; | ||
118 | |||
119 | if (old == new) | ||
120 | break; | ||
121 | |||
122 | old = atomic_cmpxchg(&nmi_running, old, new); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static void ftrace_mod_code(void) | ||
127 | { | ||
128 | /* | ||
129 | * Yes, more than one CPU process can be writing to mod_code_status. | ||
130 | * (and the code itself) | ||
131 | * But if one were to fail, then they all should, and if one were | ||
132 | * to succeed, then they all should. | ||
133 | */ | ||
134 | mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode, | ||
135 | MCOUNT_INSN_SIZE); | ||
136 | |||
137 | /* if we fail, then kill any new writers */ | ||
138 | if (mod_code_status) | ||
139 | clear_mod_flag(); | ||
140 | } | ||
141 | |||
142 | void ftrace_nmi_enter(void) | ||
143 | { | ||
144 | if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) { | ||
145 | smp_rmb(); | ||
146 | ftrace_mod_code(); | ||
147 | atomic_inc(&nmi_update_count); | ||
148 | } | ||
149 | /* Must have previous changes seen before executions */ | ||
150 | smp_mb(); | ||
151 | } | ||
152 | |||
153 | void ftrace_nmi_exit(void) | ||
154 | { | ||
155 | /* Finish all executions before clearing nmi_running */ | ||
156 | smp_mb(); | ||
157 | atomic_dec(&nmi_running); | ||
158 | } | ||
159 | |||
160 | static void wait_for_nmi_and_set_mod_flag(void) | ||
161 | { | ||
162 | if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG)) | ||
163 | return; | ||
164 | |||
165 | do { | ||
166 | cpu_relax(); | ||
167 | } while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG)); | ||
168 | |||
169 | nmi_wait_count++; | ||
170 | } | ||
171 | |||
172 | static void wait_for_nmi(void) | ||
173 | { | ||
174 | if (!atomic_read(&nmi_running)) | ||
175 | return; | ||
176 | |||
177 | do { | ||
178 | cpu_relax(); | ||
179 | } while (atomic_read(&nmi_running)); | ||
180 | |||
181 | nmi_wait_count++; | ||
182 | } | ||
183 | |||
184 | static int | ||
185 | do_ftrace_mod_code(unsigned long ip, void *new_code) | ||
186 | { | ||
187 | mod_code_ip = (void *)ip; | ||
188 | mod_code_newcode = new_code; | ||
189 | |||
190 | /* The buffers need to be visible before we let NMIs write them */ | ||
191 | smp_mb(); | ||
192 | |||
193 | wait_for_nmi_and_set_mod_flag(); | ||
194 | |||
195 | /* Make sure all running NMIs have finished before we write the code */ | ||
196 | smp_mb(); | ||
197 | |||
198 | ftrace_mod_code(); | ||
199 | |||
200 | /* Make sure the write happens before clearing the bit */ | ||
201 | smp_mb(); | ||
202 | |||
203 | clear_mod_flag(); | ||
204 | wait_for_nmi(); | ||
205 | |||
206 | return mod_code_status; | ||
207 | } | ||
208 | |||
65 | static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, | 209 | static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, |
66 | unsigned char *new_code) | 210 | unsigned char *new_code) |
67 | { | 211 | { |
@@ -86,7 +230,7 @@ static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, | |||
86 | return -EINVAL; | 230 | return -EINVAL; |
87 | 231 | ||
88 | /* replace the text with the new text */ | 232 | /* replace the text with the new text */ |
89 | if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) | 233 | if (do_ftrace_mod_code(ip, new_code)) |
90 | return -EPERM; | 234 | return -EPERM; |
91 | 235 | ||
92 | flush_icache_range(ip, ip + MCOUNT_INSN_SIZE); | 236 | flush_icache_range(ip, ip + MCOUNT_INSN_SIZE); |
diff --git a/arch/sh/kernel/gpio.c b/arch/sh/kernel/gpio.c deleted file mode 100644 index d22e5af699f9..000000000000 --- a/arch/sh/kernel/gpio.c +++ /dev/null | |||
@@ -1,584 +0,0 @@ | |||
1 | /* | ||
2 | * Pinmuxed GPIO support for SuperH. | ||
3 | * | ||
4 | * Copyright (C) 2008 Magnus Damm | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/errno.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/clk.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/bitops.h> | ||
20 | #include <linux/gpio.h> | ||
21 | |||
22 | static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r) | ||
23 | { | ||
24 | if (enum_id < r->begin) | ||
25 | return 0; | ||
26 | |||
27 | if (enum_id > r->end) | ||
28 | return 0; | ||
29 | |||
30 | return 1; | ||
31 | } | ||
32 | |||
33 | static unsigned long gpio_read_raw_reg(unsigned long reg, | ||
34 | unsigned long reg_width) | ||
35 | { | ||
36 | switch (reg_width) { | ||
37 | case 8: | ||
38 | return ctrl_inb(reg); | ||
39 | case 16: | ||
40 | return ctrl_inw(reg); | ||
41 | case 32: | ||
42 | return ctrl_inl(reg); | ||
43 | } | ||
44 | |||
45 | BUG(); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static void gpio_write_raw_reg(unsigned long reg, | ||
50 | unsigned long reg_width, | ||
51 | unsigned long data) | ||
52 | { | ||
53 | switch (reg_width) { | ||
54 | case 8: | ||
55 | ctrl_outb(data, reg); | ||
56 | return; | ||
57 | case 16: | ||
58 | ctrl_outw(data, reg); | ||
59 | return; | ||
60 | case 32: | ||
61 | ctrl_outl(data, reg); | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | BUG(); | ||
66 | } | ||
67 | |||
68 | static void gpio_write_bit(struct pinmux_data_reg *dr, | ||
69 | unsigned long in_pos, unsigned long value) | ||
70 | { | ||
71 | unsigned long pos; | ||
72 | |||
73 | pos = dr->reg_width - (in_pos + 1); | ||
74 | |||
75 | #ifdef DEBUG | ||
76 | pr_info("write_bit addr = %lx, value = %ld, pos = %ld, " | ||
77 | "r_width = %ld\n", | ||
78 | dr->reg, !!value, pos, dr->reg_width); | ||
79 | #endif | ||
80 | |||
81 | if (value) | ||
82 | set_bit(pos, &dr->reg_shadow); | ||
83 | else | ||
84 | clear_bit(pos, &dr->reg_shadow); | ||
85 | |||
86 | gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow); | ||
87 | } | ||
88 | |||
89 | static int gpio_read_reg(unsigned long reg, unsigned long reg_width, | ||
90 | unsigned long field_width, unsigned long in_pos) | ||
91 | { | ||
92 | unsigned long data, mask, pos; | ||
93 | |||
94 | data = 0; | ||
95 | mask = (1 << field_width) - 1; | ||
96 | pos = reg_width - ((in_pos + 1) * field_width); | ||
97 | |||
98 | #ifdef DEBUG | ||
99 | pr_info("read_reg: addr = %lx, pos = %ld, " | ||
100 | "r_width = %ld, f_width = %ld\n", | ||
101 | reg, pos, reg_width, field_width); | ||
102 | #endif | ||
103 | |||
104 | data = gpio_read_raw_reg(reg, reg_width); | ||
105 | return (data >> pos) & mask; | ||
106 | } | ||
107 | |||
108 | static void gpio_write_reg(unsigned long reg, unsigned long reg_width, | ||
109 | unsigned long field_width, unsigned long in_pos, | ||
110 | unsigned long value) | ||
111 | { | ||
112 | unsigned long mask, pos; | ||
113 | |||
114 | mask = (1 << field_width) - 1; | ||
115 | pos = reg_width - ((in_pos + 1) * field_width); | ||
116 | |||
117 | #ifdef DEBUG | ||
118 | pr_info("write_reg addr = %lx, value = %ld, pos = %ld, " | ||
119 | "r_width = %ld, f_width = %ld\n", | ||
120 | reg, value, pos, reg_width, field_width); | ||
121 | #endif | ||
122 | |||
123 | mask = ~(mask << pos); | ||
124 | value = value << pos; | ||
125 | |||
126 | switch (reg_width) { | ||
127 | case 8: | ||
128 | ctrl_outb((ctrl_inb(reg) & mask) | value, reg); | ||
129 | break; | ||
130 | case 16: | ||
131 | ctrl_outw((ctrl_inw(reg) & mask) | value, reg); | ||
132 | break; | ||
133 | case 32: | ||
134 | ctrl_outl((ctrl_inl(reg) & mask) | value, reg); | ||
135 | break; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) | ||
140 | { | ||
141 | struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | ||
142 | struct pinmux_data_reg *data_reg; | ||
143 | int k, n; | ||
144 | |||
145 | if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | ||
146 | return -1; | ||
147 | |||
148 | k = 0; | ||
149 | while (1) { | ||
150 | data_reg = gpioc->data_regs + k; | ||
151 | |||
152 | if (!data_reg->reg_width) | ||
153 | break; | ||
154 | |||
155 | for (n = 0; n < data_reg->reg_width; n++) { | ||
156 | if (data_reg->enum_ids[n] == gpiop->enum_id) { | ||
157 | gpiop->flags &= ~PINMUX_FLAG_DREG; | ||
158 | gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT); | ||
159 | gpiop->flags &= ~PINMUX_FLAG_DBIT; | ||
160 | gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT); | ||
161 | return 0; | ||
162 | } | ||
163 | } | ||
164 | k++; | ||
165 | } | ||
166 | |||
167 | BUG(); | ||
168 | |||
169 | return -1; | ||
170 | } | ||
171 | |||
172 | static void setup_data_regs(struct pinmux_info *gpioc) | ||
173 | { | ||
174 | struct pinmux_data_reg *drp; | ||
175 | int k; | ||
176 | |||
177 | for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++) | ||
178 | setup_data_reg(gpioc, k); | ||
179 | |||
180 | k = 0; | ||
181 | while (1) { | ||
182 | drp = gpioc->data_regs + k; | ||
183 | |||
184 | if (!drp->reg_width) | ||
185 | break; | ||
186 | |||
187 | drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width); | ||
188 | k++; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, | ||
193 | struct pinmux_data_reg **drp, int *bitp) | ||
194 | { | ||
195 | struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | ||
196 | int k, n; | ||
197 | |||
198 | if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | ||
199 | return -1; | ||
200 | |||
201 | k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT; | ||
202 | n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT; | ||
203 | *drp = gpioc->data_regs + k; | ||
204 | *bitp = n; | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id, | ||
209 | struct pinmux_cfg_reg **crp, int *indexp, | ||
210 | unsigned long **cntp) | ||
211 | { | ||
212 | struct pinmux_cfg_reg *config_reg; | ||
213 | unsigned long r_width, f_width; | ||
214 | int k, n; | ||
215 | |||
216 | k = 0; | ||
217 | while (1) { | ||
218 | config_reg = gpioc->cfg_regs + k; | ||
219 | |||
220 | r_width = config_reg->reg_width; | ||
221 | f_width = config_reg->field_width; | ||
222 | |||
223 | if (!r_width) | ||
224 | break; | ||
225 | for (n = 0; n < (r_width / f_width) * 1 << f_width; n++) { | ||
226 | if (config_reg->enum_ids[n] == enum_id) { | ||
227 | *crp = config_reg; | ||
228 | *indexp = n; | ||
229 | *cntp = &config_reg->cnt[n / (1 << f_width)]; | ||
230 | return 0; | ||
231 | } | ||
232 | } | ||
233 | k++; | ||
234 | } | ||
235 | |||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio, | ||
240 | int pos, pinmux_enum_t *enum_idp) | ||
241 | { | ||
242 | pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id; | ||
243 | pinmux_enum_t *data = gpioc->gpio_data; | ||
244 | int k; | ||
245 | |||
246 | if (!enum_in_range(enum_id, &gpioc->data)) { | ||
247 | if (!enum_in_range(enum_id, &gpioc->mark)) { | ||
248 | pr_err("non data/mark enum_id for gpio %d\n", gpio); | ||
249 | return -1; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | if (pos) { | ||
254 | *enum_idp = data[pos + 1]; | ||
255 | return pos + 1; | ||
256 | } | ||
257 | |||
258 | for (k = 0; k < gpioc->gpio_data_size; k++) { | ||
259 | if (data[k] == enum_id) { | ||
260 | *enum_idp = data[k + 1]; | ||
261 | return k + 1; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | pr_err("cannot locate data/mark enum_id for gpio %d\n", gpio); | ||
266 | return -1; | ||
267 | } | ||
268 | |||
269 | static void write_config_reg(struct pinmux_info *gpioc, | ||
270 | struct pinmux_cfg_reg *crp, | ||
271 | int index) | ||
272 | { | ||
273 | unsigned long ncomb, pos, value; | ||
274 | |||
275 | ncomb = 1 << crp->field_width; | ||
276 | pos = index / ncomb; | ||
277 | value = index % ncomb; | ||
278 | |||
279 | gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value); | ||
280 | } | ||
281 | |||
282 | static int check_config_reg(struct pinmux_info *gpioc, | ||
283 | struct pinmux_cfg_reg *crp, | ||
284 | int index) | ||
285 | { | ||
286 | unsigned long ncomb, pos, value; | ||
287 | |||
288 | ncomb = 1 << crp->field_width; | ||
289 | pos = index / ncomb; | ||
290 | value = index % ncomb; | ||
291 | |||
292 | if (gpio_read_reg(crp->reg, crp->reg_width, | ||
293 | crp->field_width, pos) == value) | ||
294 | return 0; | ||
295 | |||
296 | return -1; | ||
297 | } | ||
298 | |||
299 | enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE }; | ||
300 | |||
301 | static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | ||
302 | int pinmux_type, int cfg_mode) | ||
303 | { | ||
304 | struct pinmux_cfg_reg *cr = NULL; | ||
305 | pinmux_enum_t enum_id; | ||
306 | struct pinmux_range *range; | ||
307 | int in_range, pos, index; | ||
308 | unsigned long *cntp; | ||
309 | |||
310 | switch (pinmux_type) { | ||
311 | |||
312 | case PINMUX_TYPE_FUNCTION: | ||
313 | range = NULL; | ||
314 | break; | ||
315 | |||
316 | case PINMUX_TYPE_OUTPUT: | ||
317 | range = &gpioc->output; | ||
318 | break; | ||
319 | |||
320 | case PINMUX_TYPE_INPUT: | ||
321 | range = &gpioc->input; | ||
322 | break; | ||
323 | |||
324 | case PINMUX_TYPE_INPUT_PULLUP: | ||
325 | range = &gpioc->input_pu; | ||
326 | break; | ||
327 | |||
328 | case PINMUX_TYPE_INPUT_PULLDOWN: | ||
329 | range = &gpioc->input_pd; | ||
330 | break; | ||
331 | |||
332 | default: | ||
333 | goto out_err; | ||
334 | } | ||
335 | |||
336 | pos = 0; | ||
337 | enum_id = 0; | ||
338 | index = 0; | ||
339 | while (1) { | ||
340 | pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id); | ||
341 | if (pos <= 0) | ||
342 | goto out_err; | ||
343 | |||
344 | if (!enum_id) | ||
345 | break; | ||
346 | |||
347 | in_range = enum_in_range(enum_id, &gpioc->function); | ||
348 | if (!in_range && range) { | ||
349 | in_range = enum_in_range(enum_id, range); | ||
350 | |||
351 | if (in_range && enum_id == range->force) | ||
352 | continue; | ||
353 | } | ||
354 | |||
355 | if (!in_range) | ||
356 | continue; | ||
357 | |||
358 | if (get_config_reg(gpioc, enum_id, &cr, &index, &cntp) != 0) | ||
359 | goto out_err; | ||
360 | |||
361 | switch (cfg_mode) { | ||
362 | case GPIO_CFG_DRYRUN: | ||
363 | if (!*cntp || !check_config_reg(gpioc, cr, index)) | ||
364 | continue; | ||
365 | break; | ||
366 | |||
367 | case GPIO_CFG_REQ: | ||
368 | write_config_reg(gpioc, cr, index); | ||
369 | *cntp = *cntp + 1; | ||
370 | break; | ||
371 | |||
372 | case GPIO_CFG_FREE: | ||
373 | *cntp = *cntp - 1; | ||
374 | break; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | return 0; | ||
379 | out_err: | ||
380 | return -1; | ||
381 | } | ||
382 | |||
383 | static DEFINE_SPINLOCK(gpio_lock); | ||
384 | |||
385 | static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip) | ||
386 | { | ||
387 | return container_of(chip, struct pinmux_info, chip); | ||
388 | } | ||
389 | |||
390 | static int sh_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
391 | { | ||
392 | struct pinmux_info *gpioc = chip_to_pinmux(chip); | ||
393 | struct pinmux_data_reg *dummy; | ||
394 | unsigned long flags; | ||
395 | int i, ret, pinmux_type; | ||
396 | |||
397 | ret = -EINVAL; | ||
398 | |||
399 | if (!gpioc) | ||
400 | goto err_out; | ||
401 | |||
402 | spin_lock_irqsave(&gpio_lock, flags); | ||
403 | |||
404 | if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE) | ||
405 | goto err_unlock; | ||
406 | |||
407 | /* setup pin function here if no data is associated with pin */ | ||
408 | |||
409 | if (get_data_reg(gpioc, offset, &dummy, &i) != 0) | ||
410 | pinmux_type = PINMUX_TYPE_FUNCTION; | ||
411 | else | ||
412 | pinmux_type = PINMUX_TYPE_GPIO; | ||
413 | |||
414 | if (pinmux_type == PINMUX_TYPE_FUNCTION) { | ||
415 | if (pinmux_config_gpio(gpioc, offset, | ||
416 | pinmux_type, | ||
417 | GPIO_CFG_DRYRUN) != 0) | ||
418 | goto err_unlock; | ||
419 | |||
420 | if (pinmux_config_gpio(gpioc, offset, | ||
421 | pinmux_type, | ||
422 | GPIO_CFG_REQ) != 0) | ||
423 | BUG(); | ||
424 | } | ||
425 | |||
426 | gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | ||
427 | gpioc->gpios[offset].flags |= pinmux_type; | ||
428 | |||
429 | ret = 0; | ||
430 | err_unlock: | ||
431 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
432 | err_out: | ||
433 | return ret; | ||
434 | } | ||
435 | |||
436 | static void sh_gpio_free(struct gpio_chip *chip, unsigned offset) | ||
437 | { | ||
438 | struct pinmux_info *gpioc = chip_to_pinmux(chip); | ||
439 | unsigned long flags; | ||
440 | int pinmux_type; | ||
441 | |||
442 | if (!gpioc) | ||
443 | return; | ||
444 | |||
445 | spin_lock_irqsave(&gpio_lock, flags); | ||
446 | |||
447 | pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE; | ||
448 | pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE); | ||
449 | gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | ||
450 | gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE; | ||
451 | |||
452 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
453 | } | ||
454 | |||
455 | static int pinmux_direction(struct pinmux_info *gpioc, | ||
456 | unsigned gpio, int new_pinmux_type) | ||
457 | { | ||
458 | int pinmux_type; | ||
459 | int ret = -EINVAL; | ||
460 | |||
461 | if (!gpioc) | ||
462 | goto err_out; | ||
463 | |||
464 | pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE; | ||
465 | |||
466 | switch (pinmux_type) { | ||
467 | case PINMUX_TYPE_GPIO: | ||
468 | break; | ||
469 | case PINMUX_TYPE_OUTPUT: | ||
470 | case PINMUX_TYPE_INPUT: | ||
471 | case PINMUX_TYPE_INPUT_PULLUP: | ||
472 | case PINMUX_TYPE_INPUT_PULLDOWN: | ||
473 | pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE); | ||
474 | break; | ||
475 | default: | ||
476 | goto err_out; | ||
477 | } | ||
478 | |||
479 | if (pinmux_config_gpio(gpioc, gpio, | ||
480 | new_pinmux_type, | ||
481 | GPIO_CFG_DRYRUN) != 0) | ||
482 | goto err_out; | ||
483 | |||
484 | if (pinmux_config_gpio(gpioc, gpio, | ||
485 | new_pinmux_type, | ||
486 | GPIO_CFG_REQ) != 0) | ||
487 | BUG(); | ||
488 | |||
489 | gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE; | ||
490 | gpioc->gpios[gpio].flags |= new_pinmux_type; | ||
491 | |||
492 | ret = 0; | ||
493 | err_out: | ||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | static int sh_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
498 | { | ||
499 | struct pinmux_info *gpioc = chip_to_pinmux(chip); | ||
500 | unsigned long flags; | ||
501 | int ret; | ||
502 | |||
503 | spin_lock_irqsave(&gpio_lock, flags); | ||
504 | ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT); | ||
505 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
506 | |||
507 | return ret; | ||
508 | } | ||
509 | |||
510 | static void sh_gpio_set_value(struct pinmux_info *gpioc, | ||
511 | unsigned gpio, int value) | ||
512 | { | ||
513 | struct pinmux_data_reg *dr = NULL; | ||
514 | int bit = 0; | ||
515 | |||
516 | if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) | ||
517 | BUG(); | ||
518 | else | ||
519 | gpio_write_bit(dr, bit, value); | ||
520 | } | ||
521 | |||
522 | static int sh_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | ||
523 | int value) | ||
524 | { | ||
525 | struct pinmux_info *gpioc = chip_to_pinmux(chip); | ||
526 | unsigned long flags; | ||
527 | int ret; | ||
528 | |||
529 | sh_gpio_set_value(gpioc, offset, value); | ||
530 | spin_lock_irqsave(&gpio_lock, flags); | ||
531 | ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT); | ||
532 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
533 | |||
534 | return ret; | ||
535 | } | ||
536 | |||
537 | static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio) | ||
538 | { | ||
539 | struct pinmux_data_reg *dr = NULL; | ||
540 | int bit = 0; | ||
541 | |||
542 | if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) { | ||
543 | BUG(); | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | return gpio_read_reg(dr->reg, dr->reg_width, 1, bit); | ||
548 | } | ||
549 | |||
550 | static int sh_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
551 | { | ||
552 | return sh_gpio_get_value(chip_to_pinmux(chip), offset); | ||
553 | } | ||
554 | |||
555 | static void sh_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
556 | { | ||
557 | sh_gpio_set_value(chip_to_pinmux(chip), offset, value); | ||
558 | } | ||
559 | |||
560 | int register_pinmux(struct pinmux_info *pip) | ||
561 | { | ||
562 | struct gpio_chip *chip = &pip->chip; | ||
563 | |||
564 | pr_info("sh pinmux: %s handling gpio %d -> %d\n", | ||
565 | pip->name, pip->first_gpio, pip->last_gpio); | ||
566 | |||
567 | setup_data_regs(pip); | ||
568 | |||
569 | chip->request = sh_gpio_request; | ||
570 | chip->free = sh_gpio_free; | ||
571 | chip->direction_input = sh_gpio_direction_input; | ||
572 | chip->get = sh_gpio_get; | ||
573 | chip->direction_output = sh_gpio_direction_output; | ||
574 | chip->set = sh_gpio_set; | ||
575 | |||
576 | WARN_ON(pip->first_gpio != 0); /* needs testing */ | ||
577 | |||
578 | chip->label = pip->name; | ||
579 | chip->owner = THIS_MODULE; | ||
580 | chip->base = pip->first_gpio; | ||
581 | chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1; | ||
582 | |||
583 | return gpiochip_add(chip); | ||
584 | } | ||
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index a78be74b8d3e..1151ecdffa71 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S | |||
@@ -33,7 +33,7 @@ ENTRY(empty_zero_page) | |||
33 | .long 1 /* LOADER_TYPE */ | 33 | .long 1 /* LOADER_TYPE */ |
34 | .long 0x00000000 /* INITRD_START */ | 34 | .long 0x00000000 /* INITRD_START */ |
35 | .long 0x00000000 /* INITRD_SIZE */ | 35 | .long 0x00000000 /* INITRD_SIZE */ |
36 | #ifdef CONFIG_32BIT | 36 | #if defined(CONFIG_32BIT) && defined(CONFIG_PMB_FIXED) |
37 | .long 0x53453f00 + 32 /* "SE?" = 32 bit */ | 37 | .long 0x53453f00 + 32 /* "SE?" = 32 bit */ |
38 | #else | 38 | #else |
39 | .long 0x53453f00 + 29 /* "SE?" = 29 bit */ | 39 | .long 0x53453f00 + 29 /* "SE?" = 29 bit */ |
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c index 27ff2dc093c7..aaff0037fcd7 100644 --- a/arch/sh/kernel/idle.c +++ b/arch/sh/kernel/idle.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <asm/atomic.h> | 21 | #include <asm/atomic.h> |
22 | 22 | ||
23 | static int hlt_counter; | 23 | static int hlt_counter; |
24 | void (*pm_idle)(void); | 24 | void (*pm_idle)(void) = NULL; |
25 | void (*pm_power_off)(void); | 25 | void (*pm_power_off)(void); |
26 | EXPORT_SYMBOL(pm_power_off); | 26 | EXPORT_SYMBOL(pm_power_off); |
27 | 27 | ||
@@ -39,48 +39,92 @@ static int __init hlt_setup(char *__unused) | |||
39 | } | 39 | } |
40 | __setup("hlt", hlt_setup); | 40 | __setup("hlt", hlt_setup); |
41 | 41 | ||
42 | static inline int hlt_works(void) | ||
43 | { | ||
44 | return !hlt_counter; | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * On SMP it's slightly faster (but much more power-consuming!) | ||
49 | * to poll the ->work.need_resched flag instead of waiting for the | ||
50 | * cross-CPU IPI to arrive. Use this option with caution. | ||
51 | */ | ||
52 | static void poll_idle(void) | ||
53 | { | ||
54 | local_irq_enable(); | ||
55 | while (!need_resched()) | ||
56 | cpu_relax(); | ||
57 | } | ||
58 | |||
42 | void default_idle(void) | 59 | void default_idle(void) |
43 | { | 60 | { |
44 | if (!hlt_counter) { | 61 | if (hlt_works()) { |
45 | clear_thread_flag(TIF_POLLING_NRFLAG); | 62 | clear_thread_flag(TIF_POLLING_NRFLAG); |
46 | smp_mb__after_clear_bit(); | 63 | smp_mb__after_clear_bit(); |
47 | set_bl_bit(); | ||
48 | stop_critical_timings(); | ||
49 | 64 | ||
50 | while (!need_resched()) | 65 | if (!need_resched()) { |
66 | local_irq_enable(); | ||
51 | cpu_sleep(); | 67 | cpu_sleep(); |
68 | } else | ||
69 | local_irq_enable(); | ||
52 | 70 | ||
53 | start_critical_timings(); | ||
54 | clear_bl_bit(); | ||
55 | set_thread_flag(TIF_POLLING_NRFLAG); | 71 | set_thread_flag(TIF_POLLING_NRFLAG); |
56 | } else | 72 | } else |
57 | while (!need_resched()) | 73 | poll_idle(); |
58 | cpu_relax(); | ||
59 | } | 74 | } |
60 | 75 | ||
76 | /* | ||
77 | * The idle thread. There's no useful work to be done, so just try to conserve | ||
78 | * power and have a low exit latency (ie sit in a loop waiting for somebody to | ||
79 | * say that they'd like to reschedule) | ||
80 | */ | ||
61 | void cpu_idle(void) | 81 | void cpu_idle(void) |
62 | { | 82 | { |
83 | unsigned int cpu = smp_processor_id(); | ||
84 | |||
63 | set_thread_flag(TIF_POLLING_NRFLAG); | 85 | set_thread_flag(TIF_POLLING_NRFLAG); |
64 | 86 | ||
65 | /* endless idle loop with no priority at all */ | 87 | /* endless idle loop with no priority at all */ |
66 | while (1) { | 88 | while (1) { |
67 | void (*idle)(void) = pm_idle; | 89 | tick_nohz_stop_sched_tick(1); |
68 | 90 | ||
69 | if (!idle) | 91 | while (!need_resched() && cpu_online(cpu)) { |
70 | idle = default_idle; | 92 | check_pgt_cache(); |
93 | rmb(); | ||
71 | 94 | ||
72 | tick_nohz_stop_sched_tick(1); | 95 | local_irq_disable(); |
73 | while (!need_resched()) | 96 | /* Don't trace irqs off for idle */ |
74 | idle(); | 97 | stop_critical_timings(); |
75 | tick_nohz_restart_sched_tick(); | 98 | pm_idle(); |
99 | /* | ||
100 | * Sanity check to ensure that pm_idle() returns | ||
101 | * with IRQs enabled | ||
102 | */ | ||
103 | WARN_ON(irqs_disabled()); | ||
104 | start_critical_timings(); | ||
105 | } | ||
76 | 106 | ||
107 | tick_nohz_restart_sched_tick(); | ||
77 | preempt_enable_no_resched(); | 108 | preempt_enable_no_resched(); |
78 | schedule(); | 109 | schedule(); |
79 | preempt_disable(); | 110 | preempt_disable(); |
80 | check_pgt_cache(); | ||
81 | } | 111 | } |
82 | } | 112 | } |
83 | 113 | ||
114 | void __cpuinit select_idle_routine(void) | ||
115 | { | ||
116 | /* | ||
117 | * If a platform has set its own idle routine, leave it alone. | ||
118 | */ | ||
119 | if (pm_idle) | ||
120 | return; | ||
121 | |||
122 | if (hlt_works()) | ||
123 | pm_idle = default_idle; | ||
124 | else | ||
125 | pm_idle = poll_idle; | ||
126 | } | ||
127 | |||
84 | static void do_nothing(void *unused) | 128 | static void do_nothing(void *unused) |
85 | { | 129 | { |
86 | } | 130 | } |
diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c index b8fa6524760a..e1e1dbd19557 100644 --- a/arch/sh/kernel/io_generic.c +++ b/arch/sh/kernel/io_generic.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #define dummy_read() | 24 | #define dummy_read() |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | unsigned long generic_io_base; | 27 | unsigned long generic_io_base = 0; |
28 | 28 | ||
29 | u8 generic_inb(unsigned long port) | 29 | u8 generic_inb(unsigned long port) |
30 | { | 30 | { |
@@ -147,8 +147,10 @@ void generic_outsl(unsigned long port, const void *src, unsigned long count) | |||
147 | 147 | ||
148 | void __iomem *generic_ioport_map(unsigned long addr, unsigned int size) | 148 | void __iomem *generic_ioport_map(unsigned long addr, unsigned int size) |
149 | { | 149 | { |
150 | #ifdef P1SEG | ||
150 | if (PXSEG(addr) >= P1SEG) | 151 | if (PXSEG(addr) >= P1SEG) |
151 | return (void __iomem *)addr; | 152 | return (void __iomem *)addr; |
153 | #endif | ||
152 | 154 | ||
153 | return (void __iomem *)(addr + generic_io_base); | 155 | return (void __iomem *)(addr + generic_io_base); |
154 | } | 156 | } |
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index eac7da772fc2..e1913f28f418 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c | |||
@@ -37,7 +37,15 @@ void ack_bad_irq(unsigned int irq) | |||
37 | */ | 37 | */ |
38 | static int show_other_interrupts(struct seq_file *p, int prec) | 38 | static int show_other_interrupts(struct seq_file *p, int prec) |
39 | { | 39 | { |
40 | int j; | ||
41 | |||
42 | seq_printf(p, "%*s: ", prec, "NMI"); | ||
43 | for_each_online_cpu(j) | ||
44 | seq_printf(p, "%10u ", irq_stat[j].__nmi_count); | ||
45 | seq_printf(p, " Non-maskable interrupts\n"); | ||
46 | |||
40 | seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); | 47 | seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); |
48 | |||
41 | return 0; | 49 | return 0; |
42 | } | 50 | } |
43 | 51 | ||
@@ -255,6 +263,12 @@ void __init init_IRQ(void) | |||
255 | { | 263 | { |
256 | plat_irq_setup(); | 264 | plat_irq_setup(); |
257 | 265 | ||
266 | /* | ||
267 | * Pin any of the legacy IRQ vectors that haven't already been | ||
268 | * grabbed by the platform | ||
269 | */ | ||
270 | reserve_irq_legacy(); | ||
271 | |||
258 | /* Perform the machine specific initialisation */ | 272 | /* Perform the machine specific initialisation */ |
259 | if (sh_mv.mv_init_irq) | 273 | if (sh_mv.mv_init_irq) |
260 | sh_mv.mv_init_irq(); | 274 | sh_mv.mv_init_irq(); |
diff --git a/arch/sh/kernel/irq_32.c b/arch/sh/kernel/irq_32.c new file mode 100644 index 000000000000..e33ab15831f9 --- /dev/null +++ b/arch/sh/kernel/irq_32.c | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * SHcompact irqflags support | ||
3 | * | ||
4 | * Copyright (C) 2006 - 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/irqflags.h> | ||
11 | #include <linux/module.h> | ||
12 | |||
13 | void notrace raw_local_irq_restore(unsigned long flags) | ||
14 | { | ||
15 | unsigned long __dummy0, __dummy1; | ||
16 | |||
17 | if (flags == RAW_IRQ_DISABLED) { | ||
18 | __asm__ __volatile__ ( | ||
19 | "stc sr, %0\n\t" | ||
20 | "or #0xf0, %0\n\t" | ||
21 | "ldc %0, sr\n\t" | ||
22 | : "=&z" (__dummy0) | ||
23 | : /* no inputs */ | ||
24 | : "memory" | ||
25 | ); | ||
26 | } else { | ||
27 | __asm__ __volatile__ ( | ||
28 | "stc sr, %0\n\t" | ||
29 | "and %1, %0\n\t" | ||
30 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
31 | "stc r6_bank, %1\n\t" | ||
32 | "or %1, %0\n\t" | ||
33 | #endif | ||
34 | "ldc %0, sr\n\t" | ||
35 | : "=&r" (__dummy0), "=r" (__dummy1) | ||
36 | : "1" (~RAW_IRQ_DISABLED) | ||
37 | : "memory" | ||
38 | ); | ||
39 | } | ||
40 | } | ||
41 | EXPORT_SYMBOL(raw_local_irq_restore); | ||
42 | |||
43 | unsigned long notrace __raw_local_save_flags(void) | ||
44 | { | ||
45 | unsigned long flags; | ||
46 | |||
47 | __asm__ __volatile__ ( | ||
48 | "stc sr, %0\n\t" | ||
49 | "and #0xf0, %0\n\t" | ||
50 | : "=&z" (flags) | ||
51 | : /* no inputs */ | ||
52 | : "memory" | ||
53 | ); | ||
54 | |||
55 | return flags; | ||
56 | } | ||
57 | EXPORT_SYMBOL(__raw_local_save_flags); | ||
diff --git a/arch/sh/kernel/irq_64.c b/arch/sh/kernel/irq_64.c new file mode 100644 index 000000000000..32365ba0e039 --- /dev/null +++ b/arch/sh/kernel/irq_64.c | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * SHmedia irqflags support | ||
3 | * | ||
4 | * Copyright (C) 2006 - 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/irqflags.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <cpu/registers.h> | ||
13 | |||
14 | void notrace raw_local_irq_restore(unsigned long flags) | ||
15 | { | ||
16 | unsigned long long __dummy; | ||
17 | |||
18 | if (flags == RAW_IRQ_DISABLED) { | ||
19 | __asm__ __volatile__ ( | ||
20 | "getcon " __SR ", %0\n\t" | ||
21 | "or %0, %1, %0\n\t" | ||
22 | "putcon %0, " __SR "\n\t" | ||
23 | : "=&r" (__dummy) | ||
24 | : "r" (RAW_IRQ_DISABLED) | ||
25 | ); | ||
26 | } else { | ||
27 | __asm__ __volatile__ ( | ||
28 | "getcon " __SR ", %0\n\t" | ||
29 | "and %0, %1, %0\n\t" | ||
30 | "putcon %0, " __SR "\n\t" | ||
31 | : "=&r" (__dummy) | ||
32 | : "r" (~RAW_IRQ_DISABLED) | ||
33 | ); | ||
34 | } | ||
35 | } | ||
36 | EXPORT_SYMBOL(raw_local_irq_restore); | ||
37 | |||
38 | unsigned long notrace __raw_local_save_flags(void) | ||
39 | { | ||
40 | unsigned long flags; | ||
41 | |||
42 | __asm__ __volatile__ ( | ||
43 | "getcon " __SR ", %0\n\t" | ||
44 | "and %0, %1, %0" | ||
45 | : "=&r" (flags) | ||
46 | : "r" (RAW_IRQ_DISABLED) | ||
47 | ); | ||
48 | |||
49 | return flags; | ||
50 | } | ||
51 | EXPORT_SYMBOL(__raw_local_save_flags); | ||
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c index 7ea2704ea033..76f280223ebd 100644 --- a/arch/sh/kernel/machine_kexec.c +++ b/arch/sh/kernel/machine_kexec.c | |||
@@ -46,12 +46,6 @@ void machine_crash_shutdown(struct pt_regs *regs) | |||
46 | */ | 46 | */ |
47 | int machine_kexec_prepare(struct kimage *image) | 47 | int machine_kexec_prepare(struct kimage *image) |
48 | { | 48 | { |
49 | /* older versions of kexec-tools are passing | ||
50 | * the zImage entry point as a virtual address. | ||
51 | */ | ||
52 | if (image->start != PHYSADDR(image->start)) | ||
53 | return -EINVAL; /* upgrade your kexec-tools */ | ||
54 | |||
55 | return 0; | 49 | return 0; |
56 | } | 50 | } |
57 | 51 | ||
diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c index cbce639b108a..1652340ba3f2 100644 --- a/arch/sh/kernel/machvec.c +++ b/arch/sh/kernel/machvec.c | |||
@@ -135,5 +135,9 @@ void __init sh_mv_setup(void) | |||
135 | if (!sh_mv.mv_nr_irqs) | 135 | if (!sh_mv.mv_nr_irqs) |
136 | sh_mv.mv_nr_irqs = NR_IRQS; | 136 | sh_mv.mv_nr_irqs = NR_IRQS; |
137 | 137 | ||
138 | #ifdef P2SEG | ||
138 | __set_io_port_base(P2SEG); | 139 | __set_io_port_base(P2SEG); |
140 | #else | ||
141 | __set_io_port_base(0); | ||
142 | #endif | ||
139 | } | 143 | } |
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c index c2efdcde266f..43adddfe4c04 100644 --- a/arch/sh/kernel/module.c +++ b/arch/sh/kernel/module.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/string.h> | 32 | #include <linux/string.h> |
33 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
34 | #include <asm/unaligned.h> | 34 | #include <asm/unaligned.h> |
35 | #include <asm/dwarf.h> | ||
35 | 36 | ||
36 | void *module_alloc(unsigned long size) | 37 | void *module_alloc(unsigned long size) |
37 | { | 38 | { |
@@ -145,10 +146,16 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
145 | const Elf_Shdr *sechdrs, | 146 | const Elf_Shdr *sechdrs, |
146 | struct module *me) | 147 | struct module *me) |
147 | { | 148 | { |
148 | return module_bug_finalize(hdr, sechdrs, me); | 149 | int ret = 0; |
150 | |||
151 | ret |= module_dwarf_finalize(hdr, sechdrs, me); | ||
152 | ret |= module_bug_finalize(hdr, sechdrs, me); | ||
153 | |||
154 | return ret; | ||
149 | } | 155 | } |
150 | 156 | ||
151 | void module_arch_cleanup(struct module *mod) | 157 | void module_arch_cleanup(struct module *mod) |
152 | { | 158 | { |
153 | module_bug_cleanup(mod); | 159 | module_bug_cleanup(mod); |
160 | module_dwarf_cleanup(mod); | ||
154 | } | 161 | } |
diff --git a/arch/sh/kernel/perf_callchain.c b/arch/sh/kernel/perf_callchain.c new file mode 100644 index 000000000000..24ea837eac5b --- /dev/null +++ b/arch/sh/kernel/perf_callchain.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Performance event callchain support - SuperH architecture code | ||
3 | * | ||
4 | * Copyright (C) 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/perf_event.h> | ||
13 | #include <linux/percpu.h> | ||
14 | #include <asm/unwinder.h> | ||
15 | #include <asm/ptrace.h> | ||
16 | |||
17 | static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip) | ||
18 | { | ||
19 | if (entry->nr < PERF_MAX_STACK_DEPTH) | ||
20 | entry->ip[entry->nr++] = ip; | ||
21 | } | ||
22 | |||
23 | static void callchain_warning(void *data, char *msg) | ||
24 | { | ||
25 | } | ||
26 | |||
27 | static void | ||
28 | callchain_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
29 | { | ||
30 | } | ||
31 | |||
32 | static int callchain_stack(void *data, char *name) | ||
33 | { | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static void callchain_address(void *data, unsigned long addr, int reliable) | ||
38 | { | ||
39 | struct perf_callchain_entry *entry = data; | ||
40 | |||
41 | if (reliable) | ||
42 | callchain_store(entry, addr); | ||
43 | } | ||
44 | |||
45 | static const struct stacktrace_ops callchain_ops = { | ||
46 | .warning = callchain_warning, | ||
47 | .warning_symbol = callchain_warning_symbol, | ||
48 | .stack = callchain_stack, | ||
49 | .address = callchain_address, | ||
50 | }; | ||
51 | |||
52 | static void | ||
53 | perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry) | ||
54 | { | ||
55 | callchain_store(entry, PERF_CONTEXT_KERNEL); | ||
56 | callchain_store(entry, regs->pc); | ||
57 | |||
58 | unwind_stack(NULL, regs, NULL, &callchain_ops, entry); | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry) | ||
63 | { | ||
64 | int is_user; | ||
65 | |||
66 | if (!regs) | ||
67 | return; | ||
68 | |||
69 | is_user = user_mode(regs); | ||
70 | |||
71 | if (!current || current->pid == 0) | ||
72 | return; | ||
73 | |||
74 | if (is_user && current->state != TASK_RUNNING) | ||
75 | return; | ||
76 | |||
77 | /* | ||
78 | * Only the kernel side is implemented for now. | ||
79 | */ | ||
80 | if (!is_user) | ||
81 | perf_callchain_kernel(regs, entry); | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * No need for separate IRQ and NMI entries. | ||
86 | */ | ||
87 | static DEFINE_PER_CPU(struct perf_callchain_entry, callchain); | ||
88 | |||
89 | struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) | ||
90 | { | ||
91 | struct perf_callchain_entry *entry = &__get_cpu_var(callchain); | ||
92 | |||
93 | entry->nr = 0; | ||
94 | |||
95 | perf_do_callchain(regs, entry); | ||
96 | |||
97 | return entry; | ||
98 | } | ||
diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c new file mode 100644 index 000000000000..7ff0943e7a08 --- /dev/null +++ b/arch/sh/kernel/perf_event.c | |||
@@ -0,0 +1,312 @@ | |||
1 | /* | ||
2 | * Performance event support framework for SuperH hardware counters. | ||
3 | * | ||
4 | * Copyright (C) 2009 Paul Mundt | ||
5 | * | ||
6 | * Heavily based on the x86 and PowerPC implementations. | ||
7 | * | ||
8 | * x86: | ||
9 | * Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de> | ||
10 | * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar | ||
11 | * Copyright (C) 2009 Jaswinder Singh Rajput | ||
12 | * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter | ||
13 | * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> | ||
14 | * Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com> | ||
15 | * | ||
16 | * ppc: | ||
17 | * Copyright 2008-2009 Paul Mackerras, IBM Corporation. | ||
18 | * | ||
19 | * This file is subject to the terms and conditions of the GNU General Public | ||
20 | * License. See the file "COPYING" in the main directory of this archive | ||
21 | * for more details. | ||
22 | */ | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/perf_event.h> | ||
28 | #include <asm/processor.h> | ||
29 | |||
30 | struct cpu_hw_events { | ||
31 | struct perf_event *events[MAX_HWEVENTS]; | ||
32 | unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; | ||
33 | unsigned long active_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; | ||
34 | }; | ||
35 | |||
36 | DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); | ||
37 | |||
38 | static struct sh_pmu *sh_pmu __read_mostly; | ||
39 | |||
40 | /* Number of perf_events counting hardware events */ | ||
41 | static atomic_t num_events; | ||
42 | /* Used to avoid races in calling reserve/release_pmc_hardware */ | ||
43 | static DEFINE_MUTEX(pmc_reserve_mutex); | ||
44 | |||
45 | /* | ||
46 | * Stub these out for now, do something more profound later. | ||
47 | */ | ||
48 | int reserve_pmc_hardware(void) | ||
49 | { | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | void release_pmc_hardware(void) | ||
54 | { | ||
55 | } | ||
56 | |||
57 | static inline int sh_pmu_initialized(void) | ||
58 | { | ||
59 | return !!sh_pmu; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Release the PMU if this is the last perf_event. | ||
64 | */ | ||
65 | static void hw_perf_event_destroy(struct perf_event *event) | ||
66 | { | ||
67 | if (!atomic_add_unless(&num_events, -1, 1)) { | ||
68 | mutex_lock(&pmc_reserve_mutex); | ||
69 | if (atomic_dec_return(&num_events) == 0) | ||
70 | release_pmc_hardware(); | ||
71 | mutex_unlock(&pmc_reserve_mutex); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | static int hw_perf_cache_event(int config, int *evp) | ||
76 | { | ||
77 | unsigned long type, op, result; | ||
78 | int ev; | ||
79 | |||
80 | if (!sh_pmu->cache_events) | ||
81 | return -EINVAL; | ||
82 | |||
83 | /* unpack config */ | ||
84 | type = config & 0xff; | ||
85 | op = (config >> 8) & 0xff; | ||
86 | result = (config >> 16) & 0xff; | ||
87 | |||
88 | if (type >= PERF_COUNT_HW_CACHE_MAX || | ||
89 | op >= PERF_COUNT_HW_CACHE_OP_MAX || | ||
90 | result >= PERF_COUNT_HW_CACHE_RESULT_MAX) | ||
91 | return -EINVAL; | ||
92 | |||
93 | ev = (*sh_pmu->cache_events)[type][op][result]; | ||
94 | if (ev == 0) | ||
95 | return -EOPNOTSUPP; | ||
96 | if (ev == -1) | ||
97 | return -EINVAL; | ||
98 | *evp = ev; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int __hw_perf_event_init(struct perf_event *event) | ||
103 | { | ||
104 | struct perf_event_attr *attr = &event->attr; | ||
105 | struct hw_perf_event *hwc = &event->hw; | ||
106 | int config = -1; | ||
107 | int err; | ||
108 | |||
109 | if (!sh_pmu_initialized()) | ||
110 | return -ENODEV; | ||
111 | |||
112 | /* | ||
113 | * All of the on-chip counters are "limited", in that they have | ||
114 | * no interrupts, and are therefore unable to do sampling without | ||
115 | * further work and timer assistance. | ||
116 | */ | ||
117 | if (hwc->sample_period) | ||
118 | return -EINVAL; | ||
119 | |||
120 | /* | ||
121 | * See if we need to reserve the counter. | ||
122 | * | ||
123 | * If no events are currently in use, then we have to take a | ||
124 | * mutex to ensure that we don't race with another task doing | ||
125 | * reserve_pmc_hardware or release_pmc_hardware. | ||
126 | */ | ||
127 | err = 0; | ||
128 | if (!atomic_inc_not_zero(&num_events)) { | ||
129 | mutex_lock(&pmc_reserve_mutex); | ||
130 | if (atomic_read(&num_events) == 0 && | ||
131 | reserve_pmc_hardware()) | ||
132 | err = -EBUSY; | ||
133 | else | ||
134 | atomic_inc(&num_events); | ||
135 | mutex_unlock(&pmc_reserve_mutex); | ||
136 | } | ||
137 | |||
138 | if (err) | ||
139 | return err; | ||
140 | |||
141 | event->destroy = hw_perf_event_destroy; | ||
142 | |||
143 | switch (attr->type) { | ||
144 | case PERF_TYPE_RAW: | ||
145 | config = attr->config & sh_pmu->raw_event_mask; | ||
146 | break; | ||
147 | case PERF_TYPE_HW_CACHE: | ||
148 | err = hw_perf_cache_event(attr->config, &config); | ||
149 | if (err) | ||
150 | return err; | ||
151 | break; | ||
152 | case PERF_TYPE_HARDWARE: | ||
153 | if (attr->config >= sh_pmu->max_events) | ||
154 | return -EINVAL; | ||
155 | |||
156 | config = sh_pmu->event_map(attr->config); | ||
157 | break; | ||
158 | } | ||
159 | |||
160 | if (config == -1) | ||
161 | return -EINVAL; | ||
162 | |||
163 | hwc->config |= config; | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static void sh_perf_event_update(struct perf_event *event, | ||
169 | struct hw_perf_event *hwc, int idx) | ||
170 | { | ||
171 | u64 prev_raw_count, new_raw_count; | ||
172 | s64 delta; | ||
173 | int shift = 0; | ||
174 | |||
175 | /* | ||
176 | * Depending on the counter configuration, they may or may not | ||
177 | * be chained, in which case the previous counter value can be | ||
178 | * updated underneath us if the lower-half overflows. | ||
179 | * | ||
180 | * Our tactic to handle this is to first atomically read and | ||
181 | * exchange a new raw count - then add that new-prev delta | ||
182 | * count to the generic counter atomically. | ||
183 | * | ||
184 | * As there is no interrupt associated with the overflow events, | ||
185 | * this is the simplest approach for maintaining consistency. | ||
186 | */ | ||
187 | again: | ||
188 | prev_raw_count = atomic64_read(&hwc->prev_count); | ||
189 | new_raw_count = sh_pmu->read(idx); | ||
190 | |||
191 | if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count, | ||
192 | new_raw_count) != prev_raw_count) | ||
193 | goto again; | ||
194 | |||
195 | /* | ||
196 | * Now we have the new raw value and have updated the prev | ||
197 | * timestamp already. We can now calculate the elapsed delta | ||
198 | * (counter-)time and add that to the generic counter. | ||
199 | * | ||
200 | * Careful, not all hw sign-extends above the physical width | ||
201 | * of the count. | ||
202 | */ | ||
203 | delta = (new_raw_count << shift) - (prev_raw_count << shift); | ||
204 | delta >>= shift; | ||
205 | |||
206 | atomic64_add(delta, &event->count); | ||
207 | } | ||
208 | |||
209 | static void sh_pmu_disable(struct perf_event *event) | ||
210 | { | ||
211 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
212 | struct hw_perf_event *hwc = &event->hw; | ||
213 | int idx = hwc->idx; | ||
214 | |||
215 | clear_bit(idx, cpuc->active_mask); | ||
216 | sh_pmu->disable(hwc, idx); | ||
217 | |||
218 | barrier(); | ||
219 | |||
220 | sh_perf_event_update(event, &event->hw, idx); | ||
221 | |||
222 | cpuc->events[idx] = NULL; | ||
223 | clear_bit(idx, cpuc->used_mask); | ||
224 | |||
225 | perf_event_update_userpage(event); | ||
226 | } | ||
227 | |||
228 | static int sh_pmu_enable(struct perf_event *event) | ||
229 | { | ||
230 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
231 | struct hw_perf_event *hwc = &event->hw; | ||
232 | int idx = hwc->idx; | ||
233 | |||
234 | if (test_and_set_bit(idx, cpuc->used_mask)) { | ||
235 | idx = find_first_zero_bit(cpuc->used_mask, sh_pmu->num_events); | ||
236 | if (idx == sh_pmu->num_events) | ||
237 | return -EAGAIN; | ||
238 | |||
239 | set_bit(idx, cpuc->used_mask); | ||
240 | hwc->idx = idx; | ||
241 | } | ||
242 | |||
243 | sh_pmu->disable(hwc, idx); | ||
244 | |||
245 | cpuc->events[idx] = event; | ||
246 | set_bit(idx, cpuc->active_mask); | ||
247 | |||
248 | sh_pmu->enable(hwc, idx); | ||
249 | |||
250 | perf_event_update_userpage(event); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static void sh_pmu_read(struct perf_event *event) | ||
256 | { | ||
257 | sh_perf_event_update(event, &event->hw, event->hw.idx); | ||
258 | } | ||
259 | |||
260 | static const struct pmu pmu = { | ||
261 | .enable = sh_pmu_enable, | ||
262 | .disable = sh_pmu_disable, | ||
263 | .read = sh_pmu_read, | ||
264 | }; | ||
265 | |||
266 | const struct pmu *hw_perf_event_init(struct perf_event *event) | ||
267 | { | ||
268 | int err = __hw_perf_event_init(event); | ||
269 | if (unlikely(err)) { | ||
270 | if (event->destroy) | ||
271 | event->destroy(event); | ||
272 | return ERR_PTR(err); | ||
273 | } | ||
274 | |||
275 | return &pmu; | ||
276 | } | ||
277 | |||
278 | void hw_perf_event_setup(int cpu) | ||
279 | { | ||
280 | struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu); | ||
281 | |||
282 | memset(cpuhw, 0, sizeof(struct cpu_hw_events)); | ||
283 | } | ||
284 | |||
285 | void hw_perf_enable(void) | ||
286 | { | ||
287 | if (!sh_pmu_initialized()) | ||
288 | return; | ||
289 | |||
290 | sh_pmu->enable_all(); | ||
291 | } | ||
292 | |||
293 | void hw_perf_disable(void) | ||
294 | { | ||
295 | if (!sh_pmu_initialized()) | ||
296 | return; | ||
297 | |||
298 | sh_pmu->disable_all(); | ||
299 | } | ||
300 | |||
301 | int register_sh_pmu(struct sh_pmu *pmu) | ||
302 | { | ||
303 | if (sh_pmu) | ||
304 | return -EBUSY; | ||
305 | sh_pmu = pmu; | ||
306 | |||
307 | pr_info("Performance Events: %s support registered\n", pmu->name); | ||
308 | |||
309 | WARN_ON(pmu->num_events > MAX_HWEVENTS); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 0673c4746be3..d8af889366a4 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c | |||
@@ -134,7 +134,10 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
134 | regs.regs[5] = (unsigned long)fn; | 134 | regs.regs[5] = (unsigned long)fn; |
135 | 135 | ||
136 | regs.pc = (unsigned long)kernel_thread_helper; | 136 | regs.pc = (unsigned long)kernel_thread_helper; |
137 | regs.sr = (1 << 30); | 137 | regs.sr = SR_MD; |
138 | #if defined(CONFIG_SH_FPU) | ||
139 | regs.sr |= SR_FD; | ||
140 | #endif | ||
138 | 141 | ||
139 | /* Ok, create the new process.. */ | 142 | /* Ok, create the new process.. */ |
140 | pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, | 143 | pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, |
@@ -142,6 +145,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
142 | 145 | ||
143 | return pid; | 146 | return pid; |
144 | } | 147 | } |
148 | EXPORT_SYMBOL(kernel_thread); | ||
145 | 149 | ||
146 | /* | 150 | /* |
147 | * Free current thread data structures etc.. | 151 | * Free current thread data structures etc.. |
@@ -186,6 +190,16 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
186 | 190 | ||
187 | return fpvalid; | 191 | return fpvalid; |
188 | } | 192 | } |
193 | EXPORT_SYMBOL(dump_fpu); | ||
194 | |||
195 | /* | ||
196 | * This gets called before we allocate a new thread and copy | ||
197 | * the current task into it. | ||
198 | */ | ||
199 | void prepare_to_copy(struct task_struct *tsk) | ||
200 | { | ||
201 | unlazy_fpu(tsk, task_pt_regs(tsk)); | ||
202 | } | ||
189 | 203 | ||
190 | asmlinkage void ret_from_fork(void); | 204 | asmlinkage void ret_from_fork(void); |
191 | 205 | ||
@@ -195,16 +209,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
195 | { | 209 | { |
196 | struct thread_info *ti = task_thread_info(p); | 210 | struct thread_info *ti = task_thread_info(p); |
197 | struct pt_regs *childregs; | 211 | struct pt_regs *childregs; |
198 | #if defined(CONFIG_SH_FPU) || defined(CONFIG_SH_DSP) | 212 | #if defined(CONFIG_SH_DSP) |
199 | struct task_struct *tsk = current; | 213 | struct task_struct *tsk = current; |
200 | #endif | 214 | #endif |
201 | 215 | ||
202 | #if defined(CONFIG_SH_FPU) | ||
203 | unlazy_fpu(tsk, regs); | ||
204 | p->thread.fpu = tsk->thread.fpu; | ||
205 | copy_to_stopped_child_used_math(p); | ||
206 | #endif | ||
207 | |||
208 | #if defined(CONFIG_SH_DSP) | 216 | #if defined(CONFIG_SH_DSP) |
209 | if (is_dsp_enabled(tsk)) { | 217 | if (is_dsp_enabled(tsk)) { |
210 | /* We can use the __save_dsp or just copy the struct: | 218 | /* We can use the __save_dsp or just copy the struct: |
@@ -224,6 +232,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
224 | } else { | 232 | } else { |
225 | childregs->regs[15] = (unsigned long)childregs; | 233 | childregs->regs[15] = (unsigned long)childregs; |
226 | ti->addr_limit = KERNEL_DS; | 234 | ti->addr_limit = KERNEL_DS; |
235 | ti->status &= ~TS_USEDFPU; | ||
236 | p->fpu_counter = 0; | ||
227 | } | 237 | } |
228 | 238 | ||
229 | if (clone_flags & CLONE_SETTLS) | 239 | if (clone_flags & CLONE_SETTLS) |
@@ -288,9 +298,13 @@ static void ubc_set_tracing(int asid, unsigned long pc) | |||
288 | __notrace_funcgraph struct task_struct * | 298 | __notrace_funcgraph struct task_struct * |
289 | __switch_to(struct task_struct *prev, struct task_struct *next) | 299 | __switch_to(struct task_struct *prev, struct task_struct *next) |
290 | { | 300 | { |
291 | #if defined(CONFIG_SH_FPU) | 301 | struct thread_struct *next_t = &next->thread; |
302 | |||
292 | unlazy_fpu(prev, task_pt_regs(prev)); | 303 | unlazy_fpu(prev, task_pt_regs(prev)); |
293 | #endif | 304 | |
305 | /* we're going to use this soon, after a few expensive things */ | ||
306 | if (next->fpu_counter > 5) | ||
307 | prefetch(&next_t->fpu.hard); | ||
294 | 308 | ||
295 | #ifdef CONFIG_MMU | 309 | #ifdef CONFIG_MMU |
296 | /* | 310 | /* |
@@ -321,6 +335,14 @@ __switch_to(struct task_struct *prev, struct task_struct *next) | |||
321 | #endif | 335 | #endif |
322 | } | 336 | } |
323 | 337 | ||
338 | /* | ||
339 | * If the task has used fpu the last 5 timeslices, just do a full | ||
340 | * restore of the math state immediately to avoid the trap; the | ||
341 | * chances of needing FPU soon are obviously high now | ||
342 | */ | ||
343 | if (next->fpu_counter > 5) | ||
344 | fpu_state_restore(task_pt_regs(next)); | ||
345 | |||
324 | return prev; | 346 | return prev; |
325 | } | 347 | } |
326 | 348 | ||
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 1192398ef582..359b8a2f4d2e 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c | |||
@@ -335,6 +335,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
335 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, | 335 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, |
336 | ®s, 0, NULL, NULL); | 336 | ®s, 0, NULL, NULL); |
337 | } | 337 | } |
338 | EXPORT_SYMBOL(kernel_thread); | ||
338 | 339 | ||
339 | /* | 340 | /* |
340 | * Free current thread data structures etc.. | 341 | * Free current thread data structures etc.. |
@@ -417,6 +418,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
417 | return 0; /* Task didn't use the fpu at all. */ | 418 | return 0; /* Task didn't use the fpu at all. */ |
418 | #endif | 419 | #endif |
419 | } | 420 | } |
421 | EXPORT_SYMBOL(dump_fpu); | ||
420 | 422 | ||
421 | asmlinkage void ret_from_fork(void); | 423 | asmlinkage void ret_from_fork(void); |
422 | 424 | ||
diff --git a/arch/sh/kernel/return_address.c b/arch/sh/kernel/return_address.c new file mode 100644 index 000000000000..df3ab5811074 --- /dev/null +++ b/arch/sh/kernel/return_address.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/return_address.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Matt Fleming | ||
5 | * Copyright (C) 2009 Paul Mundt | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file "COPYING" in the main directory of this archive | ||
9 | * for more details. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <asm/dwarf.h> | ||
13 | |||
14 | #ifdef CONFIG_DWARF_UNWINDER | ||
15 | |||
16 | void *return_address(unsigned int depth) | ||
17 | { | ||
18 | struct dwarf_frame *frame; | ||
19 | unsigned long ra; | ||
20 | int i; | ||
21 | |||
22 | for (i = 0, frame = NULL, ra = 0; i <= depth; i++) { | ||
23 | struct dwarf_frame *tmp; | ||
24 | |||
25 | tmp = dwarf_unwind_stack(ra, frame); | ||
26 | |||
27 | if (frame) | ||
28 | dwarf_free_frame(frame); | ||
29 | |||
30 | frame = tmp; | ||
31 | |||
32 | if (!frame || !frame->return_addr) | ||
33 | break; | ||
34 | |||
35 | ra = frame->return_addr; | ||
36 | } | ||
37 | |||
38 | /* Failed to unwind the stack to the specified depth. */ | ||
39 | WARN_ON(i != depth + 1); | ||
40 | |||
41 | if (frame) | ||
42 | dwarf_free_frame(frame); | ||
43 | |||
44 | return (void *)ra; | ||
45 | } | ||
46 | |||
47 | #else | ||
48 | |||
49 | void *return_address(unsigned int depth) | ||
50 | { | ||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | #endif | ||
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 99b4fb553bf1..5a947a2567e4 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
@@ -453,6 +453,10 @@ void __init setup_arch(char **cmdline_p) | |||
453 | 453 | ||
454 | paging_init(); | 454 | paging_init(); |
455 | 455 | ||
456 | #ifdef CONFIG_PMB_ENABLE | ||
457 | pmb_init(); | ||
458 | #endif | ||
459 | |||
456 | #ifdef CONFIG_SMP | 460 | #ifdef CONFIG_SMP |
457 | plat_smp_setup(); | 461 | plat_smp_setup(); |
458 | #endif | 462 | #endif |
diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c index 444cce3ae921..3896f26efa4a 100644 --- a/arch/sh/kernel/sh_ksyms_32.c +++ b/arch/sh/kernel/sh_ksyms_32.c | |||
@@ -1,37 +1,11 @@ | |||
1 | #include <linux/module.h> | 1 | #include <linux/module.h> |
2 | #include <linux/smp.h> | 2 | #include <linux/string.h> |
3 | #include <linux/user.h> | 3 | #include <linux/uaccess.h> |
4 | #include <linux/elfcore.h> | 4 | #include <linux/delay.h> |
5 | #include <linux/sched.h> | 5 | #include <linux/mm.h> |
6 | #include <linux/in6.h> | ||
7 | #include <linux/interrupt.h> | ||
8 | #include <linux/vmalloc.h> | ||
9 | #include <linux/pci.h> | ||
10 | #include <linux/irq.h> | ||
11 | #include <asm/sections.h> | ||
12 | #include <asm/processor.h> | ||
13 | #include <asm/uaccess.h> | ||
14 | #include <asm/checksum.h> | 6 | #include <asm/checksum.h> |
15 | #include <asm/io.h> | 7 | #include <asm/sections.h> |
16 | #include <asm/delay.h> | ||
17 | #include <asm/tlbflush.h> | ||
18 | #include <asm/cacheflush.h> | ||
19 | #include <asm/ftrace.h> | ||
20 | |||
21 | extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); | ||
22 | |||
23 | /* platform dependent support */ | ||
24 | EXPORT_SYMBOL(dump_fpu); | ||
25 | EXPORT_SYMBOL(kernel_thread); | ||
26 | EXPORT_SYMBOL(strlen); | ||
27 | |||
28 | /* PCI exports */ | ||
29 | #ifdef CONFIG_PCI | ||
30 | EXPORT_SYMBOL(pci_alloc_consistent); | ||
31 | EXPORT_SYMBOL(pci_free_consistent); | ||
32 | #endif | ||
33 | 8 | ||
34 | /* mem exports */ | ||
35 | EXPORT_SYMBOL(memchr); | 9 | EXPORT_SYMBOL(memchr); |
36 | EXPORT_SYMBOL(memcpy); | 10 | EXPORT_SYMBOL(memcpy); |
37 | EXPORT_SYMBOL(memset); | 11 | EXPORT_SYMBOL(memset); |
@@ -40,6 +14,13 @@ EXPORT_SYMBOL(__copy_user); | |||
40 | EXPORT_SYMBOL(__udelay); | 14 | EXPORT_SYMBOL(__udelay); |
41 | EXPORT_SYMBOL(__ndelay); | 15 | EXPORT_SYMBOL(__ndelay); |
42 | EXPORT_SYMBOL(__const_udelay); | 16 | EXPORT_SYMBOL(__const_udelay); |
17 | EXPORT_SYMBOL(strlen); | ||
18 | EXPORT_SYMBOL(csum_partial); | ||
19 | EXPORT_SYMBOL(csum_partial_copy_generic); | ||
20 | EXPORT_SYMBOL(copy_page); | ||
21 | EXPORT_SYMBOL(__clear_user); | ||
22 | EXPORT_SYMBOL(_ebss); | ||
23 | EXPORT_SYMBOL(empty_zero_page); | ||
43 | 24 | ||
44 | #define DECLARE_EXPORT(name) \ | 25 | #define DECLARE_EXPORT(name) \ |
45 | extern void name(void);EXPORT_SYMBOL(name) | 26 | extern void name(void);EXPORT_SYMBOL(name) |
@@ -107,30 +88,6 @@ DECLARE_EXPORT(__sdivsi3_i4); | |||
107 | DECLARE_EXPORT(__udivsi3_i4); | 88 | DECLARE_EXPORT(__udivsi3_i4); |
108 | DECLARE_EXPORT(__sdivsi3_i4i); | 89 | DECLARE_EXPORT(__sdivsi3_i4i); |
109 | DECLARE_EXPORT(__udivsi3_i4i); | 90 | DECLARE_EXPORT(__udivsi3_i4i); |
110 | |||
111 | #if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \ | ||
112 | defined(CONFIG_SH7705_CACHE_32KB)) | ||
113 | /* needed by some modules */ | ||
114 | EXPORT_SYMBOL(flush_cache_all); | ||
115 | EXPORT_SYMBOL(flush_cache_range); | ||
116 | EXPORT_SYMBOL(flush_dcache_page); | ||
117 | #endif | ||
118 | |||
119 | #ifdef CONFIG_MCOUNT | 91 | #ifdef CONFIG_MCOUNT |
120 | DECLARE_EXPORT(mcount); | 92 | DECLARE_EXPORT(mcount); |
121 | #endif | 93 | #endif |
122 | EXPORT_SYMBOL(csum_partial); | ||
123 | EXPORT_SYMBOL(csum_partial_copy_generic); | ||
124 | #ifdef CONFIG_IPV6 | ||
125 | EXPORT_SYMBOL(csum_ipv6_magic); | ||
126 | #endif | ||
127 | EXPORT_SYMBOL(copy_page); | ||
128 | EXPORT_SYMBOL(__clear_user); | ||
129 | EXPORT_SYMBOL(_ebss); | ||
130 | EXPORT_SYMBOL(empty_zero_page); | ||
131 | |||
132 | #ifndef CONFIG_CACHE_OFF | ||
133 | EXPORT_SYMBOL(__flush_purge_region); | ||
134 | EXPORT_SYMBOL(__flush_wback_region); | ||
135 | EXPORT_SYMBOL(__flush_invalidate_region); | ||
136 | #endif | ||
diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c index d008e17eb257..45afa5c51f67 100644 --- a/arch/sh/kernel/sh_ksyms_64.c +++ b/arch/sh/kernel/sh_ksyms_64.c | |||
@@ -24,16 +24,6 @@ | |||
24 | #include <asm/delay.h> | 24 | #include <asm/delay.h> |
25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
26 | 26 | ||
27 | extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); | ||
28 | |||
29 | /* platform dependent support */ | ||
30 | EXPORT_SYMBOL(dump_fpu); | ||
31 | EXPORT_SYMBOL(kernel_thread); | ||
32 | |||
33 | #ifdef CONFIG_VT | ||
34 | EXPORT_SYMBOL(screen_info); | ||
35 | #endif | ||
36 | |||
37 | EXPORT_SYMBOL(__put_user_asm_b); | 27 | EXPORT_SYMBOL(__put_user_asm_b); |
38 | EXPORT_SYMBOL(__put_user_asm_w); | 28 | EXPORT_SYMBOL(__put_user_asm_w); |
39 | EXPORT_SYMBOL(__put_user_asm_l); | 29 | EXPORT_SYMBOL(__put_user_asm_l); |
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 3db37425210d..12815ce01ecd 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c | |||
@@ -67,7 +67,8 @@ sys_sigsuspend(old_sigset_t mask, | |||
67 | 67 | ||
68 | current->state = TASK_INTERRUPTIBLE; | 68 | current->state = TASK_INTERRUPTIBLE; |
69 | schedule(); | 69 | schedule(); |
70 | set_thread_flag(TIF_RESTORE_SIGMASK); | 70 | set_restore_sigmask(); |
71 | |||
71 | return -ERESTARTNOHAND; | 72 | return -ERESTARTNOHAND; |
72 | } | 73 | } |
73 | 74 | ||
@@ -590,7 +591,7 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) | |||
590 | if (try_to_freeze()) | 591 | if (try_to_freeze()) |
591 | goto no_signal; | 592 | goto no_signal; |
592 | 593 | ||
593 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 594 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) |
594 | oldset = ¤t->saved_sigmask; | 595 | oldset = ¤t->saved_sigmask; |
595 | else | 596 | else |
596 | oldset = ¤t->blocked; | 597 | oldset = ¤t->blocked; |
@@ -602,12 +603,13 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) | |||
602 | /* Whee! Actually deliver the signal. */ | 603 | /* Whee! Actually deliver the signal. */ |
603 | if (handle_signal(signr, &ka, &info, oldset, | 604 | if (handle_signal(signr, &ka, &info, oldset, |
604 | regs, save_r0) == 0) { | 605 | regs, save_r0) == 0) { |
605 | /* a signal was successfully delivered; the saved | 606 | /* |
607 | * A signal was successfully delivered; the saved | ||
606 | * sigmask will have been stored in the signal frame, | 608 | * sigmask will have been stored in the signal frame, |
607 | * and will be restored by sigreturn, so we can simply | 609 | * and will be restored by sigreturn, so we can simply |
608 | * clear the TIF_RESTORE_SIGMASK flag */ | 610 | * clear the TS_RESTORE_SIGMASK flag |
609 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 611 | */ |
610 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 612 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
611 | 613 | ||
612 | tracehook_signal_handler(signr, &info, &ka, regs, | 614 | tracehook_signal_handler(signr, &info, &ka, regs, |
613 | test_thread_flag(TIF_SINGLESTEP)); | 615 | test_thread_flag(TIF_SINGLESTEP)); |
@@ -631,10 +633,12 @@ no_signal: | |||
631 | } | 633 | } |
632 | } | 634 | } |
633 | 635 | ||
634 | /* if there's no signal to deliver, we just put the saved sigmask | 636 | /* |
635 | * back */ | 637 | * If there's no signal to deliver, we just put the saved sigmask |
636 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | 638 | * back. |
637 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 639 | */ |
640 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) { | ||
641 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; | ||
638 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 642 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
639 | } | 643 | } |
640 | } | 644 | } |
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 74793c80a57a..feb3dddd3192 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c | |||
@@ -101,7 +101,7 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
101 | if (try_to_freeze()) | 101 | if (try_to_freeze()) |
102 | goto no_signal; | 102 | goto no_signal; |
103 | 103 | ||
104 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 104 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) |
105 | oldset = ¤t->saved_sigmask; | 105 | oldset = ¤t->saved_sigmask; |
106 | else if (!oldset) | 106 | else if (!oldset) |
107 | oldset = ¤t->blocked; | 107 | oldset = ¤t->blocked; |
@@ -115,11 +115,9 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
115 | /* | 115 | /* |
116 | * If a signal was successfully delivered, the | 116 | * If a signal was successfully delivered, the |
117 | * saved sigmask is in its frame, and we can | 117 | * saved sigmask is in its frame, and we can |
118 | * clear the TIF_RESTORE_SIGMASK flag. | 118 | * clear the TS_RESTORE_SIGMASK flag. |
119 | */ | 119 | */ |
120 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 120 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
121 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
122 | |||
123 | tracehook_signal_handler(signr, &info, &ka, regs, 0); | 121 | tracehook_signal_handler(signr, &info, &ka, regs, 0); |
124 | return 1; | 122 | return 1; |
125 | } | 123 | } |
@@ -146,8 +144,8 @@ no_signal: | |||
146 | } | 144 | } |
147 | 145 | ||
148 | /* No signal to deliver -- put the saved sigmask back */ | 146 | /* No signal to deliver -- put the saved sigmask back */ |
149 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | 147 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) { |
150 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 148 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
151 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 149 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
152 | } | 150 | } |
153 | 151 | ||
@@ -176,6 +174,7 @@ sys_sigsuspend(old_sigset_t mask, | |||
176 | while (1) { | 174 | while (1) { |
177 | current->state = TASK_INTERRUPTIBLE; | 175 | current->state = TASK_INTERRUPTIBLE; |
178 | schedule(); | 176 | schedule(); |
177 | set_restore_sigmask(); | ||
179 | regs->pc += 4; /* because sys_sigreturn decrements the pc */ | 178 | regs->pc += 4; /* because sys_sigreturn decrements the pc */ |
180 | if (do_signal(regs, &saveset)) { | 179 | if (do_signal(regs, &saveset)) { |
181 | /* pc now points at signal handler. Need to decrement | 180 | /* pc now points at signal handler. Need to decrement |
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 160db1003cfb..983e0792d5f3 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c | |||
@@ -122,7 +122,9 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
122 | stack_start.bss_start = 0; /* don't clear bss for secondary cpus */ | 122 | stack_start.bss_start = 0; /* don't clear bss for secondary cpus */ |
123 | stack_start.start_kernel_fn = start_secondary; | 123 | stack_start.start_kernel_fn = start_secondary; |
124 | 124 | ||
125 | flush_cache_all(); | 125 | flush_icache_range((unsigned long)&stack_start, |
126 | (unsigned long)&stack_start + sizeof(stack_start)); | ||
127 | wmb(); | ||
126 | 128 | ||
127 | plat_start_cpu(cpu, (unsigned long)_stext); | 129 | plat_start_cpu(cpu, (unsigned long)_stext); |
128 | 130 | ||
diff --git a/arch/sh/kernel/topology.c b/arch/sh/kernel/topology.c index 0838942b7083..9b0b633b6c92 100644 --- a/arch/sh/kernel/topology.c +++ b/arch/sh/kernel/topology.c | |||
@@ -16,6 +16,32 @@ | |||
16 | 16 | ||
17 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 17 | static DEFINE_PER_CPU(struct cpu, cpu_devices); |
18 | 18 | ||
19 | cpumask_t cpu_core_map[NR_CPUS]; | ||
20 | |||
21 | static cpumask_t cpu_coregroup_map(unsigned int cpu) | ||
22 | { | ||
23 | /* | ||
24 | * Presently all SH-X3 SMP cores are multi-cores, so just keep it | ||
25 | * simple until we have a method for determining topology.. | ||
26 | */ | ||
27 | return cpu_possible_map; | ||
28 | } | ||
29 | |||
30 | const struct cpumask *cpu_coregroup_mask(unsigned int cpu) | ||
31 | { | ||
32 | return &cpu_core_map[cpu]; | ||
33 | } | ||
34 | |||
35 | int arch_update_cpu_topology(void) | ||
36 | { | ||
37 | unsigned int cpu; | ||
38 | |||
39 | for_each_possible_cpu(cpu) | ||
40 | cpu_core_map[cpu] = cpu_coregroup_map(cpu); | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
19 | static int __init topology_init(void) | 45 | static int __init topology_init(void) |
20 | { | 46 | { |
21 | int i, ret; | 47 | int i, ret; |
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index a8396f36bd14..7b036339dc92 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c | |||
@@ -9,8 +9,8 @@ | |||
9 | #include <asm/unwinder.h> | 9 | #include <asm/unwinder.h> |
10 | #include <asm/system.h> | 10 | #include <asm/system.h> |
11 | 11 | ||
12 | #ifdef CONFIG_BUG | 12 | #ifdef CONFIG_GENERIC_BUG |
13 | void handle_BUG(struct pt_regs *regs) | 13 | static void handle_BUG(struct pt_regs *regs) |
14 | { | 14 | { |
15 | const struct bug_entry *bug; | 15 | const struct bug_entry *bug; |
16 | unsigned long bugaddr = regs->pc; | 16 | unsigned long bugaddr = regs->pc; |
@@ -81,7 +81,7 @@ BUILD_TRAP_HANDLER(bug) | |||
81 | SIGTRAP) == NOTIFY_STOP) | 81 | SIGTRAP) == NOTIFY_STOP) |
82 | return; | 82 | return; |
83 | 83 | ||
84 | #ifdef CONFIG_BUG | 84 | #ifdef CONFIG_GENERIC_BUG |
85 | if (__kernel_text_address(instruction_pointer(regs))) { | 85 | if (__kernel_text_address(instruction_pointer(regs))) { |
86 | insn_size_t insn = *(insn_size_t *)instruction_pointer(regs); | 86 | insn_size_t insn = *(insn_size_t *)instruction_pointer(regs); |
87 | if (insn == TRAPA_BUG_OPCODE) | 87 | if (insn == TRAPA_BUG_OPCODE) |
@@ -95,9 +95,11 @@ BUILD_TRAP_HANDLER(bug) | |||
95 | 95 | ||
96 | BUILD_TRAP_HANDLER(nmi) | 96 | BUILD_TRAP_HANDLER(nmi) |
97 | { | 97 | { |
98 | unsigned int cpu = smp_processor_id(); | ||
98 | TRAP_HANDLER_DECL; | 99 | TRAP_HANDLER_DECL; |
99 | 100 | ||
100 | nmi_enter(); | 101 | nmi_enter(); |
102 | nmi_count(cpu)++; | ||
101 | 103 | ||
102 | switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) { | 104 | switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) { |
103 | case NOTIFY_OK: | 105 | case NOTIFY_OK: |
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 7a2ee3a6b8e7..3da5a125d884 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/kexec.h> | 25 | #include <linux/kexec.h> |
26 | #include <linux/limits.h> | 26 | #include <linux/limits.h> |
27 | #include <linux/proc_fs.h> | 27 | #include <linux/proc_fs.h> |
28 | #include <linux/seq_file.h> | ||
28 | #include <linux/sysfs.h> | 29 | #include <linux/sysfs.h> |
29 | #include <asm/system.h> | 30 | #include <asm/system.h> |
30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
@@ -68,61 +69,49 @@ static const char *se_usermode_action[] = { | |||
68 | "signal+warn" | 69 | "signal+warn" |
69 | }; | 70 | }; |
70 | 71 | ||
71 | static int | 72 | static int alignment_proc_show(struct seq_file *m, void *v) |
72 | proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, | ||
73 | void *data) | ||
74 | { | 73 | { |
75 | char *p = page; | 74 | seq_printf(m, "User:\t\t%lu\n", se_user); |
76 | int len; | 75 | seq_printf(m, "System:\t\t%lu\n", se_sys); |
77 | 76 | seq_printf(m, "Half:\t\t%lu\n", se_half); | |
78 | p += sprintf(p, "User:\t\t%lu\n", se_user); | 77 | seq_printf(m, "Word:\t\t%lu\n", se_word); |
79 | p += sprintf(p, "System:\t\t%lu\n", se_sys); | 78 | seq_printf(m, "DWord:\t\t%lu\n", se_dword); |
80 | p += sprintf(p, "Half:\t\t%lu\n", se_half); | 79 | seq_printf(m, "Multi:\t\t%lu\n", se_multi); |
81 | p += sprintf(p, "Word:\t\t%lu\n", se_word); | 80 | seq_printf(m, "User faults:\t%i (%s)\n", se_usermode, |
82 | p += sprintf(p, "DWord:\t\t%lu\n", se_dword); | ||
83 | p += sprintf(p, "Multi:\t\t%lu\n", se_multi); | ||
84 | p += sprintf(p, "User faults:\t%i (%s)\n", se_usermode, | ||
85 | se_usermode_action[se_usermode]); | 81 | se_usermode_action[se_usermode]); |
86 | p += sprintf(p, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn, | 82 | seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn, |
87 | se_kernmode_warn ? "+warn" : ""); | 83 | se_kernmode_warn ? "+warn" : ""); |
88 | 84 | return 0; | |
89 | len = (p - page) - off; | ||
90 | if (len < 0) | ||
91 | len = 0; | ||
92 | |||
93 | *eof = (len <= count) ? 1 : 0; | ||
94 | *start = page + off; | ||
95 | |||
96 | return len; | ||
97 | } | 85 | } |
98 | 86 | ||
99 | static int proc_alignment_write(struct file *file, const char __user *buffer, | 87 | static int alignment_proc_open(struct inode *inode, struct file *file) |
100 | unsigned long count, void *data) | ||
101 | { | 88 | { |
102 | char mode; | 89 | return single_open(file, alignment_proc_show, NULL); |
103 | |||
104 | if (count > 0) { | ||
105 | if (get_user(mode, buffer)) | ||
106 | return -EFAULT; | ||
107 | if (mode >= '0' && mode <= '5') | ||
108 | se_usermode = mode - '0'; | ||
109 | } | ||
110 | return count; | ||
111 | } | 90 | } |
112 | 91 | ||
113 | static int proc_alignment_kern_write(struct file *file, const char __user *buffer, | 92 | static ssize_t alignment_proc_write(struct file *file, |
114 | unsigned long count, void *data) | 93 | const char __user *buffer, size_t count, loff_t *pos) |
115 | { | 94 | { |
95 | int *data = PDE(file->f_path.dentry->d_inode)->data; | ||
116 | char mode; | 96 | char mode; |
117 | 97 | ||
118 | if (count > 0) { | 98 | if (count > 0) { |
119 | if (get_user(mode, buffer)) | 99 | if (get_user(mode, buffer)) |
120 | return -EFAULT; | 100 | return -EFAULT; |
121 | if (mode >= '0' && mode <= '1') | 101 | if (mode >= '0' && mode <= '5') |
122 | se_kernmode_warn = mode - '0'; | 102 | *data = mode - '0'; |
123 | } | 103 | } |
124 | return count; | 104 | return count; |
125 | } | 105 | } |
106 | |||
107 | static const struct file_operations alignment_proc_fops = { | ||
108 | .owner = THIS_MODULE, | ||
109 | .open = alignment_proc_open, | ||
110 | .read = seq_read, | ||
111 | .llseek = seq_lseek, | ||
112 | .release = single_release, | ||
113 | .write = alignment_proc_write, | ||
114 | }; | ||
126 | #endif | 115 | #endif |
127 | 116 | ||
128 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top) | 117 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top) |
@@ -945,14 +934,9 @@ void __init trap_init(void) | |||
945 | set_exception_table_evt(0x800, do_reserved_inst); | 934 | set_exception_table_evt(0x800, do_reserved_inst); |
946 | set_exception_table_evt(0x820, do_illegal_slot_inst); | 935 | set_exception_table_evt(0x820, do_illegal_slot_inst); |
947 | #elif defined(CONFIG_SH_FPU) | 936 | #elif defined(CONFIG_SH_FPU) |
948 | #ifdef CONFIG_CPU_SUBTYPE_SHX3 | ||
949 | set_exception_table_evt(0xd80, fpu_state_restore_trap_handler); | ||
950 | set_exception_table_evt(0xda0, fpu_state_restore_trap_handler); | ||
951 | #else | ||
952 | set_exception_table_evt(0x800, fpu_state_restore_trap_handler); | 937 | set_exception_table_evt(0x800, fpu_state_restore_trap_handler); |
953 | set_exception_table_evt(0x820, fpu_state_restore_trap_handler); | 938 | set_exception_table_evt(0x820, fpu_state_restore_trap_handler); |
954 | #endif | 939 | #endif |
955 | #endif | ||
956 | 940 | ||
957 | #ifdef CONFIG_CPU_SH2 | 941 | #ifdef CONFIG_CPU_SH2 |
958 | set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler); | 942 | set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler); |
@@ -1011,20 +995,16 @@ static int __init alignment_init(void) | |||
1011 | if (!dir) | 995 | if (!dir) |
1012 | return -ENOMEM; | 996 | return -ENOMEM; |
1013 | 997 | ||
1014 | res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, dir); | 998 | res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir, |
999 | &alignment_proc_fops, &se_usermode); | ||
1015 | if (!res) | 1000 | if (!res) |
1016 | return -ENOMEM; | 1001 | return -ENOMEM; |
1017 | 1002 | ||
1018 | res->read_proc = proc_alignment_read; | 1003 | res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir, |
1019 | res->write_proc = proc_alignment_write; | 1004 | &alignment_proc_fops, &se_kernmode_warn); |
1020 | |||
1021 | res = create_proc_entry("kernel_alignment", S_IWUSR | S_IRUGO, dir); | ||
1022 | if (!res) | 1005 | if (!res) |
1023 | return -ENOMEM; | 1006 | return -ENOMEM; |
1024 | 1007 | ||
1025 | res->read_proc = proc_alignment_read; | ||
1026 | res->write_proc = proc_alignment_kern_write; | ||
1027 | |||
1028 | return 0; | 1008 | return 0; |
1029 | } | 1009 | } |
1030 | 1010 | ||