diff options
Diffstat (limited to 'arch/sh/kernel')
39 files changed, 2533 insertions, 409 deletions
diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32 index 9411e3e31e68..f2245ebf0b31 100644 --- a/arch/sh/kernel/Makefile_32 +++ b/arch/sh/kernel/Makefile_32 | |||
@@ -9,10 +9,10 @@ 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 idle.o io.o io_generic.o irq.o \ | 12 | obj-y := debugtraps.o dumpstack.o idle.o io.o io_generic.o irq.o \ |
13 | machvec.o process_32.o ptrace_32.o setup.o signal_32.o \ | 13 | machvec.o process_32.o ptrace_32.o setup.o signal_32.o \ |
14 | sys_sh.o sys_sh32.o syscalls_32.o time.o topology.o \ | 14 | sys_sh.o sys_sh32.o syscalls_32.o time.o topology.o \ |
15 | traps.o traps_32.o | 15 | traps.o traps_32.o unwinder.o |
16 | 16 | ||
17 | obj-y += cpu/ | 17 | obj-y += cpu/ |
18 | obj-$(CONFIG_VSYSCALL) += vsyscall/ | 18 | obj-$(CONFIG_VSYSCALL) += vsyscall/ |
@@ -29,8 +29,11 @@ obj-$(CONFIG_IO_TRAPPED) += io_trapped.o | |||
29 | obj-$(CONFIG_KPROBES) += kprobes.o | 29 | obj-$(CONFIG_KPROBES) += kprobes.o |
30 | obj-$(CONFIG_GENERIC_GPIO) += gpio.o | 30 | obj-$(CONFIG_GENERIC_GPIO) += gpio.o |
31 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 31 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
32 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o | ||
33 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | ||
32 | obj-$(CONFIG_DUMP_CODE) += disassemble.o | 34 | obj-$(CONFIG_DUMP_CODE) += disassemble.o |
33 | obj-$(CONFIG_HIBERNATION) += swsusp.o | 35 | obj-$(CONFIG_HIBERNATION) += swsusp.o |
36 | obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o | ||
34 | 37 | ||
35 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o | 38 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o |
36 | 39 | ||
diff --git a/arch/sh/kernel/Makefile_64 b/arch/sh/kernel/Makefile_64 index 67b9f6c6326b..639ee514266c 100644 --- a/arch/sh/kernel/Makefile_64 +++ b/arch/sh/kernel/Makefile_64 | |||
@@ -2,7 +2,7 @@ extra-y := head_64.o init_task.o vmlinux.lds | |||
2 | 2 | ||
3 | obj-y := debugtraps.o idle.o io.o io_generic.o irq.o machvec.o process_64.o \ | 3 | obj-y := debugtraps.o idle.o io.o io_generic.o irq.o machvec.o process_64.o \ |
4 | ptrace_64.o setup.o signal_64.o sys_sh.o sys_sh64.o \ | 4 | ptrace_64.o setup.o signal_64.o sys_sh.o sys_sh64.o \ |
5 | syscalls_64.o time.o topology.o traps.o traps_64.o | 5 | syscalls_64.o time.o topology.o traps.o traps_64.o unwinder.o |
6 | 6 | ||
7 | obj-y += cpu/ | 7 | obj-y += cpu/ |
8 | obj-$(CONFIG_SMP) += smp.o | 8 | obj-$(CONFIG_SMP) += smp.o |
@@ -13,6 +13,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | |||
13 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 13 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
14 | obj-$(CONFIG_IO_TRAPPED) += io_trapped.o | 14 | obj-$(CONFIG_IO_TRAPPED) += io_trapped.o |
15 | obj-$(CONFIG_GENERIC_GPIO) += gpio.o | 15 | obj-$(CONFIG_GENERIC_GPIO) += gpio.o |
16 | obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o | ||
16 | 17 | ||
17 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o | 18 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o |
18 | 19 | ||
diff --git a/arch/sh/kernel/asm-offsets.c b/arch/sh/kernel/asm-offsets.c index 99aceb28ee24..d218e808294e 100644 --- a/arch/sh/kernel/asm-offsets.c +++ b/arch/sh/kernel/asm-offsets.c | |||
@@ -26,6 +26,7 @@ int main(void) | |||
26 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); | 26 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); |
27 | DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count)); | 27 | DEFINE(TI_PRE_COUNT, offsetof(struct thread_info, preempt_count)); |
28 | DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block)); | 28 | DEFINE(TI_RESTART_BLOCK,offsetof(struct thread_info, restart_block)); |
29 | DEFINE(TI_SIZE, sizeof(struct thread_info)); | ||
29 | 30 | ||
30 | #ifdef CONFIG_HIBERNATION | 31 | #ifdef CONFIG_HIBERNATION |
31 | DEFINE(PBE_ADDRESS, offsetof(struct pbe, address)); | 32 | DEFINE(PBE_ADDRESS, offsetof(struct pbe, address)); |
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile index eecad7cbd61e..3d6b9312dc47 100644 --- a/arch/sh/kernel/cpu/Makefile +++ b/arch/sh/kernel/cpu/Makefile | |||
@@ -19,4 +19,4 @@ obj-$(CONFIG_UBC_WAKEUP) += ubc.o | |||
19 | obj-$(CONFIG_SH_ADC) += adc.o | 19 | obj-$(CONFIG_SH_ADC) += adc.o |
20 | obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o | 20 | obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o |
21 | 21 | ||
22 | obj-y += irq/ init.o clock.o | 22 | obj-y += irq/ init.o clock.o hwblk.o |
diff --git a/arch/sh/kernel/cpu/hwblk.c b/arch/sh/kernel/cpu/hwblk.c new file mode 100644 index 000000000000..c0ad7d46e784 --- /dev/null +++ b/arch/sh/kernel/cpu/hwblk.c | |||
@@ -0,0 +1,155 @@ | |||
1 | #include <linux/clk.h> | ||
2 | #include <linux/compiler.h> | ||
3 | #include <linux/slab.h> | ||
4 | #include <linux/io.h> | ||
5 | #include <linux/spinlock.h> | ||
6 | #include <asm/suspend.h> | ||
7 | #include <asm/hwblk.h> | ||
8 | #include <asm/clock.h> | ||
9 | |||
10 | static DEFINE_SPINLOCK(hwblk_lock); | ||
11 | |||
12 | static void hwblk_area_mod_cnt(struct hwblk_info *info, | ||
13 | int area, int counter, int value, int goal) | ||
14 | { | ||
15 | struct hwblk_area *hap = info->areas + area; | ||
16 | |||
17 | hap->cnt[counter] += value; | ||
18 | |||
19 | if (hap->cnt[counter] != goal) | ||
20 | return; | ||
21 | |||
22 | if (hap->flags & HWBLK_AREA_FLAG_PARENT) | ||
23 | hwblk_area_mod_cnt(info, hap->parent, counter, value, goal); | ||
24 | } | ||
25 | |||
26 | |||
27 | static int __hwblk_mod_cnt(struct hwblk_info *info, int hwblk, | ||
28 | int counter, int value, int goal) | ||
29 | { | ||
30 | struct hwblk *hp = info->hwblks + hwblk; | ||
31 | |||
32 | hp->cnt[counter] += value; | ||
33 | if (hp->cnt[counter] == goal) | ||
34 | hwblk_area_mod_cnt(info, hp->area, counter, value, goal); | ||
35 | |||
36 | return hp->cnt[counter]; | ||
37 | } | ||
38 | |||
39 | static void hwblk_mod_cnt(struct hwblk_info *info, int hwblk, | ||
40 | int counter, int value, int goal) | ||
41 | { | ||
42 | unsigned long flags; | ||
43 | |||
44 | spin_lock_irqsave(&hwblk_lock, flags); | ||
45 | __hwblk_mod_cnt(info, hwblk, counter, value, goal); | ||
46 | spin_unlock_irqrestore(&hwblk_lock, flags); | ||
47 | } | ||
48 | |||
49 | void hwblk_cnt_inc(struct hwblk_info *info, int hwblk, int counter) | ||
50 | { | ||
51 | hwblk_mod_cnt(info, hwblk, counter, 1, 1); | ||
52 | } | ||
53 | |||
54 | void hwblk_cnt_dec(struct hwblk_info *info, int hwblk, int counter) | ||
55 | { | ||
56 | hwblk_mod_cnt(info, hwblk, counter, -1, 0); | ||
57 | } | ||
58 | |||
59 | void hwblk_enable(struct hwblk_info *info, int hwblk) | ||
60 | { | ||
61 | struct hwblk *hp = info->hwblks + hwblk; | ||
62 | unsigned long tmp; | ||
63 | unsigned long flags; | ||
64 | int ret; | ||
65 | |||
66 | spin_lock_irqsave(&hwblk_lock, flags); | ||
67 | |||
68 | ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, 1, 1); | ||
69 | if (ret == 1) { | ||
70 | tmp = __raw_readl(hp->mstp); | ||
71 | tmp &= ~(1 << hp->bit); | ||
72 | __raw_writel(tmp, hp->mstp); | ||
73 | } | ||
74 | |||
75 | spin_unlock_irqrestore(&hwblk_lock, flags); | ||
76 | } | ||
77 | |||
78 | void hwblk_disable(struct hwblk_info *info, int hwblk) | ||
79 | { | ||
80 | struct hwblk *hp = info->hwblks + hwblk; | ||
81 | unsigned long tmp; | ||
82 | unsigned long flags; | ||
83 | int ret; | ||
84 | |||
85 | spin_lock_irqsave(&hwblk_lock, flags); | ||
86 | |||
87 | ret = __hwblk_mod_cnt(info, hwblk, HWBLK_CNT_USAGE, -1, 0); | ||
88 | if (ret == 0) { | ||
89 | tmp = __raw_readl(hp->mstp); | ||
90 | tmp |= 1 << hp->bit; | ||
91 | __raw_writel(tmp, hp->mstp); | ||
92 | } | ||
93 | |||
94 | spin_unlock_irqrestore(&hwblk_lock, flags); | ||
95 | } | ||
96 | |||
97 | struct hwblk_info *hwblk_info; | ||
98 | |||
99 | int __init hwblk_register(struct hwblk_info *info) | ||
100 | { | ||
101 | hwblk_info = info; | ||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | int __init __weak arch_hwblk_init(void) | ||
106 | { | ||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | int __weak arch_hwblk_sleep_mode(void) | ||
111 | { | ||
112 | return SUSP_SH_SLEEP; | ||
113 | } | ||
114 | |||
115 | int __init hwblk_init(void) | ||
116 | { | ||
117 | return arch_hwblk_init(); | ||
118 | } | ||
119 | |||
120 | /* allow clocks to enable and disable hardware blocks */ | ||
121 | static int sh_hwblk_clk_enable(struct clk *clk) | ||
122 | { | ||
123 | if (!hwblk_info) | ||
124 | return -ENOENT; | ||
125 | |||
126 | hwblk_enable(hwblk_info, clk->arch_flags); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | static void sh_hwblk_clk_disable(struct clk *clk) | ||
131 | { | ||
132 | if (hwblk_info) | ||
133 | hwblk_disable(hwblk_info, clk->arch_flags); | ||
134 | } | ||
135 | |||
136 | static struct clk_ops sh_hwblk_clk_ops = { | ||
137 | .enable = sh_hwblk_clk_enable, | ||
138 | .disable = sh_hwblk_clk_disable, | ||
139 | .recalc = followparent_recalc, | ||
140 | }; | ||
141 | |||
142 | int __init sh_hwblk_clk_register(struct clk *clks, int nr) | ||
143 | { | ||
144 | struct clk *clkp; | ||
145 | int ret = 0; | ||
146 | int k; | ||
147 | |||
148 | for (k = 0; !ret && (k < nr); k++) { | ||
149 | clkp = clks + k; | ||
150 | clkp->ops = &sh_hwblk_clk_ops; | ||
151 | ret |= clk_register(clkp); | ||
152 | } | ||
153 | |||
154 | return ret; | ||
155 | } | ||
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index ad85421099cd..d40b9db5be03 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * CPU init code | 4 | * CPU init code |
5 | * | 5 | * |
6 | * Copyright (C) 2002 - 2007 Paul Mundt | 6 | * Copyright (C) 2002 - 2009 Paul Mundt |
7 | * Copyright (C) 2003 Richard Curnow | 7 | * Copyright (C) 2003 Richard Curnow |
8 | * | 8 | * |
9 | * This file is subject to the terms and conditions of the GNU General Public | 9 | * This file is subject to the terms and conditions of the GNU General Public |
@@ -62,6 +62,37 @@ static void __init speculative_execution_init(void) | |||
62 | #define speculative_execution_init() do { } while (0) | 62 | #define speculative_execution_init() do { } while (0) |
63 | #endif | 63 | #endif |
64 | 64 | ||
65 | #ifdef CONFIG_CPU_SH4A | ||
66 | #define EXPMASK 0xff2f0004 | ||
67 | #define EXPMASK_RTEDS (1 << 0) | ||
68 | #define EXPMASK_BRDSSLP (1 << 1) | ||
69 | #define EXPMASK_MMCAW (1 << 4) | ||
70 | |||
71 | static void __init expmask_init(void) | ||
72 | { | ||
73 | unsigned long expmask = __raw_readl(EXPMASK); | ||
74 | |||
75 | /* | ||
76 | * Future proofing. | ||
77 | * | ||
78 | * Disable support for slottable sleep instruction | ||
79 | * and non-nop instructions in the rte delay slot. | ||
80 | */ | ||
81 | expmask &= ~(EXPMASK_RTEDS | EXPMASK_BRDSSLP); | ||
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 | |||
89 | __raw_writel(expmask, EXPMASK); | ||
90 | ctrl_barrier(); | ||
91 | } | ||
92 | #else | ||
93 | #define expmask_init() do { } while (0) | ||
94 | #endif | ||
95 | |||
65 | /* 2nd-level cache init */ | 96 | /* 2nd-level cache init */ |
66 | void __uses_jump_to_uncached __attribute__ ((weak)) l2_cache_init(void) | 97 | void __uses_jump_to_uncached __attribute__ ((weak)) l2_cache_init(void) |
67 | { | 98 | { |
@@ -321,4 +352,5 @@ asmlinkage void __init sh_cpu_init(void) | |||
321 | #endif | 352 | #endif |
322 | 353 | ||
323 | speculative_execution_init(); | 354 | speculative_execution_init(); |
355 | expmask_init(); | ||
324 | } | 356 | } |
diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S index becc54c45692..c8a4331d9b8d 100644 --- a/arch/sh/kernel/cpu/sh2/entry.S +++ b/arch/sh/kernel/cpu/sh2/entry.S | |||
@@ -227,8 +227,9 @@ ENTRY(sh_bios_handler) | |||
227 | mov.l @r15+, r14 | 227 | mov.l @r15+, r14 |
228 | add #8,r15 | 228 | add #8,r15 |
229 | lds.l @r15+, pr | 229 | lds.l @r15+, pr |
230 | mov.l @r15+,r15 | ||
230 | rte | 231 | rte |
231 | mov.l @r15+,r15 | 232 | nop |
232 | .align 2 | 233 | .align 2 |
233 | 1: .long gdb_vbr_vector | 234 | 1: .long gdb_vbr_vector |
234 | #endif /* CONFIG_SH_STANDARD_BIOS */ | 235 | #endif /* CONFIG_SH_STANDARD_BIOS */ |
diff --git a/arch/sh/kernel/cpu/sh2a/entry.S b/arch/sh/kernel/cpu/sh2a/entry.S index ab3903eeda5c..222742ddc0d6 100644 --- a/arch/sh/kernel/cpu/sh2a/entry.S +++ b/arch/sh/kernel/cpu/sh2a/entry.S | |||
@@ -176,8 +176,9 @@ ENTRY(sh_bios_handler) | |||
176 | movml.l @r15+,r14 | 176 | movml.l @r15+,r14 |
177 | add #8,r15 | 177 | add #8,r15 |
178 | lds.l @r15+, pr | 178 | lds.l @r15+, pr |
179 | mov.l @r15+,r15 | ||
179 | rte | 180 | rte |
180 | mov.l @r15+,r15 | 181 | nop |
181 | .align 2 | 182 | .align 2 |
182 | 1: .long gdb_vbr_vector | 183 | 1: .long gdb_vbr_vector |
183 | #endif /* CONFIG_SH_STANDARD_BIOS */ | 184 | #endif /* CONFIG_SH_STANDARD_BIOS */ |
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 3cb531f233f2..67ad6467c694 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S | |||
@@ -137,6 +137,7 @@ ENTRY(tlb_protection_violation_store) | |||
137 | mov #1, r5 | 137 | mov #1, r5 |
138 | 138 | ||
139 | call_dpf: | 139 | call_dpf: |
140 | setup_frame_reg | ||
140 | mov.l 1f, r0 | 141 | mov.l 1f, r0 |
141 | mov r5, r8 | 142 | mov r5, r8 |
142 | mov.l @r0, r6 | 143 | mov.l @r0, r6 |
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile index ebdd391d5f42..12cddf4c721d 100644 --- a/arch/sh/kernel/cpu/sh4a/Makefile +++ b/arch/sh/kernel/cpu/sh4a/Makefile | |||
@@ -25,9 +25,9 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o | |||
25 | clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o | 25 | clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o |
26 | clock-$(CONFIG_CPU_SUBTYPE_SH7786) := clock-sh7786.o | 26 | clock-$(CONFIG_CPU_SUBTYPE_SH7786) := clock-sh7786.o |
27 | clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o | 27 | clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o |
28 | clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o | 28 | clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o hwblk-sh7722.o |
29 | clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o | 29 | clock-$(CONFIG_CPU_SUBTYPE_SH7723) := clock-sh7723.o hwblk-sh7723.o |
30 | clock-$(CONFIG_CPU_SUBTYPE_SH7724) := clock-sh7724.o | 30 | clock-$(CONFIG_CPU_SUBTYPE_SH7724) := clock-sh7724.o hwblk-sh7724.o |
31 | clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7366.o | 31 | clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7366.o |
32 | clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o | 32 | clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o |
33 | 33 | ||
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c index 40f859354f79..5b1bbbe63b1b 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <asm/clock.h> | 24 | #include <asm/clock.h> |
25 | #include <asm/hwblk.h> | ||
26 | #include <cpu/sh7722.h> | ||
25 | 27 | ||
26 | /* SH7722 registers */ | 28 | /* SH7722 registers */ |
27 | #define FRQCR 0xa4150000 | 29 | #define FRQCR 0xa4150000 |
@@ -30,9 +32,6 @@ | |||
30 | #define SCLKBCR 0xa415000c | 32 | #define SCLKBCR 0xa415000c |
31 | #define IRDACLKCR 0xa4150018 | 33 | #define IRDACLKCR 0xa4150018 |
32 | #define PLLCR 0xa4150024 | 34 | #define PLLCR 0xa4150024 |
33 | #define MSTPCR0 0xa4150030 | ||
34 | #define MSTPCR1 0xa4150034 | ||
35 | #define MSTPCR2 0xa4150038 | ||
36 | #define DLLFRQ 0xa4150050 | 35 | #define DLLFRQ 0xa4150050 |
37 | 36 | ||
38 | /* Fixed 32 KHz root clock for RTC and Power Management purposes */ | 37 | /* Fixed 32 KHz root clock for RTC and Power Management purposes */ |
@@ -140,35 +139,37 @@ struct clk div6_clks[] = { | |||
140 | SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0), | 139 | SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0), |
141 | }; | 140 | }; |
142 | 141 | ||
143 | #define MSTP(_str, _parent, _reg, _bit, _flags) \ | 142 | #define R_CLK &r_clk |
144 | SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _flags) | 143 | #define P_CLK &div4_clks[DIV4_P] |
144 | #define B_CLK &div4_clks[DIV4_B] | ||
145 | #define U_CLK &div4_clks[DIV4_U] | ||
145 | 146 | ||
146 | static struct clk mstp_clks[] = { | 147 | static struct clk mstp_clks[] = { |
147 | MSTP("uram0", &div4_clks[DIV4_U], MSTPCR0, 28, CLK_ENABLE_ON_INIT), | 148 | SH_HWBLK_CLK("uram0", -1, U_CLK, HWBLK_URAM, CLK_ENABLE_ON_INIT), |
148 | MSTP("xymem0", &div4_clks[DIV4_B], MSTPCR0, 26, CLK_ENABLE_ON_INIT), | 149 | SH_HWBLK_CLK("xymem0", -1, B_CLK, HWBLK_XYMEM, CLK_ENABLE_ON_INIT), |
149 | MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0), | 150 | SH_HWBLK_CLK("tmu0", -1, P_CLK, HWBLK_TMU, 0), |
150 | MSTP("cmt0", &r_clk, MSTPCR0, 14, 0), | 151 | SH_HWBLK_CLK("cmt0", -1, R_CLK, HWBLK_CMT, 0), |
151 | MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0), | 152 | SH_HWBLK_CLK("rwdt0", -1, R_CLK, HWBLK_RWDT, 0), |
152 | MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0), | 153 | SH_HWBLK_CLK("flctl0", -1, P_CLK, HWBLK_FLCTL, 0), |
153 | MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 7, 0), | 154 | SH_HWBLK_CLK("scif0", -1, P_CLK, HWBLK_SCIF0, 0), |
154 | MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 6, 0), | 155 | SH_HWBLK_CLK("scif1", -1, P_CLK, HWBLK_SCIF1, 0), |
155 | MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 5, 0), | 156 | SH_HWBLK_CLK("scif2", -1, P_CLK, HWBLK_SCIF2, 0), |
156 | 157 | ||
157 | MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0), | 158 | SH_HWBLK_CLK("i2c0", -1, P_CLK, HWBLK_IIC, 0), |
158 | MSTP("rtc0", &r_clk, MSTPCR1, 8, 0), | 159 | SH_HWBLK_CLK("rtc0", -1, R_CLK, HWBLK_RTC, 0), |
159 | 160 | ||
160 | MSTP("sdhi0", &div4_clks[DIV4_P], MSTPCR2, 18, 0), | 161 | SH_HWBLK_CLK("sdhi0", -1, P_CLK, HWBLK_SDHI, 0), |
161 | MSTP("keysc0", &r_clk, MSTPCR2, 14, 0), | 162 | SH_HWBLK_CLK("keysc0", -1, R_CLK, HWBLK_KEYSC, 0), |
162 | MSTP("usbf0", &div4_clks[DIV4_P], MSTPCR2, 11, 0), | 163 | SH_HWBLK_CLK("usbf0", -1, P_CLK, HWBLK_USBF, 0), |
163 | MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 9, 0), | 164 | SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0), |
164 | MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0), | 165 | SH_HWBLK_CLK("siu0", -1, B_CLK, HWBLK_SIU, 0), |
165 | MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0), | 166 | SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0), |
166 | MSTP("jpu0", &div4_clks[DIV4_B], MSTPCR2, 6, CLK_ENABLE_ON_INIT), | 167 | SH_HWBLK_CLK("jpu0", -1, B_CLK, HWBLK_JPU, CLK_ENABLE_ON_INIT), |
167 | MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0), | 168 | SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU, 0), |
168 | MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0), | 169 | SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU, 0), |
169 | MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, CLK_ENABLE_ON_INIT), | 170 | SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU, CLK_ENABLE_ON_INIT), |
170 | MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, CLK_ENABLE_ON_INIT), | 171 | SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT), |
171 | MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0), | 172 | SH_HWBLK_CLK("lcdc0", -1, P_CLK, HWBLK_LCDC, 0), |
172 | }; | 173 | }; |
173 | 174 | ||
174 | int __init arch_clk_init(void) | 175 | int __init arch_clk_init(void) |
@@ -191,7 +192,7 @@ int __init arch_clk_init(void) | |||
191 | ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks)); | 192 | ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks)); |
192 | 193 | ||
193 | if (!ret) | 194 | if (!ret) |
194 | ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks)); | 195 | ret = sh_hwblk_clk_register(mstp_clks, ARRAY_SIZE(mstp_clks)); |
195 | 196 | ||
196 | return ret; | 197 | return ret; |
197 | } | 198 | } |
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c index e67c2678b8ae..e5c63911403c 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7723.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <asm/clock.h> | 24 | #include <asm/clock.h> |
25 | #include <asm/hwblk.h> | ||
26 | #include <cpu/sh7723.h> | ||
25 | 27 | ||
26 | /* SH7723 registers */ | 28 | /* SH7723 registers */ |
27 | #define FRQCR 0xa4150000 | 29 | #define FRQCR 0xa4150000 |
@@ -30,9 +32,6 @@ | |||
30 | #define SCLKBCR 0xa415000c | 32 | #define SCLKBCR 0xa415000c |
31 | #define IRDACLKCR 0xa4150018 | 33 | #define IRDACLKCR 0xa4150018 |
32 | #define PLLCR 0xa4150024 | 34 | #define PLLCR 0xa4150024 |
33 | #define MSTPCR0 0xa4150030 | ||
34 | #define MSTPCR1 0xa4150034 | ||
35 | #define MSTPCR2 0xa4150038 | ||
36 | #define DLLFRQ 0xa4150050 | 35 | #define DLLFRQ 0xa4150050 |
37 | 36 | ||
38 | /* Fixed 32 KHz root clock for RTC and Power Management purposes */ | 37 | /* Fixed 32 KHz root clock for RTC and Power Management purposes */ |
@@ -140,60 +139,64 @@ struct clk div6_clks[] = { | |||
140 | SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0), | 139 | SH_CLK_DIV6("video_clk", &pll_clk, VCLKCR, 0), |
141 | }; | 140 | }; |
142 | 141 | ||
143 | #define MSTP(_str, _parent, _reg, _bit, _force_on, _need_cpg, _need_ram) \ | 142 | #define R_CLK (&r_clk) |
144 | SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _force_on * CLK_ENABLE_ON_INIT) | 143 | #define P_CLK (&div4_clks[DIV4_P]) |
144 | #define B_CLK (&div4_clks[DIV4_B]) | ||
145 | #define U_CLK (&div4_clks[DIV4_U]) | ||
146 | #define I_CLK (&div4_clks[DIV4_I]) | ||
147 | #define SH_CLK (&div4_clks[DIV4_SH]) | ||
145 | 148 | ||
146 | static struct clk mstp_clks[] = { | 149 | static struct clk mstp_clks[] = { |
147 | /* See page 60 of Datasheet V1.0: Overview -> Block Diagram */ | 150 | /* See page 60 of Datasheet V1.0: Overview -> Block Diagram */ |
148 | MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, 1, 1, 0), | 151 | SH_HWBLK_CLK("tlb0", -1, I_CLK, HWBLK_TLB, CLK_ENABLE_ON_INIT), |
149 | MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, 1, 1, 0), | 152 | SH_HWBLK_CLK("ic0", -1, I_CLK, HWBLK_IC, CLK_ENABLE_ON_INIT), |
150 | MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, 1, 1, 0), | 153 | SH_HWBLK_CLK("oc0", -1, I_CLK, HWBLK_OC, CLK_ENABLE_ON_INIT), |
151 | MSTP("l2c0", &div4_clks[DIV4_SH], MSTPCR0, 28, 1, 1, 0), | 154 | SH_HWBLK_CLK("l2c0", -1, SH_CLK, HWBLK_L2C, CLK_ENABLE_ON_INIT), |
152 | MSTP("ilmem0", &div4_clks[DIV4_I], MSTPCR0, 27, 1, 1, 0), | 155 | SH_HWBLK_CLK("ilmem0", -1, I_CLK, HWBLK_ILMEM, CLK_ENABLE_ON_INIT), |
153 | MSTP("fpu0", &div4_clks[DIV4_I], MSTPCR0, 24, 1, 1, 0), | 156 | SH_HWBLK_CLK("fpu0", -1, I_CLK, HWBLK_FPU, CLK_ENABLE_ON_INIT), |
154 | MSTP("intc0", &div4_clks[DIV4_I], MSTPCR0, 22, 1, 1, 0), | 157 | SH_HWBLK_CLK("intc0", -1, I_CLK, HWBLK_INTC, CLK_ENABLE_ON_INIT), |
155 | MSTP("dmac0", &div4_clks[DIV4_B], MSTPCR0, 21, 0, 1, 1), | 158 | SH_HWBLK_CLK("dmac0", -1, B_CLK, HWBLK_DMAC0, 0), |
156 | MSTP("sh0", &div4_clks[DIV4_SH], MSTPCR0, 20, 0, 1, 0), | 159 | SH_HWBLK_CLK("sh0", -1, SH_CLK, HWBLK_SHYWAY, CLK_ENABLE_ON_INIT), |
157 | MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0, 1, 0), | 160 | SH_HWBLK_CLK("hudi0", -1, P_CLK, HWBLK_HUDI, 0), |
158 | MSTP("ubc0", &div4_clks[DIV4_I], MSTPCR0, 17, 0, 1, 0), | 161 | SH_HWBLK_CLK("ubc0", -1, I_CLK, HWBLK_UBC, 0), |
159 | MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0, 1, 0), | 162 | SH_HWBLK_CLK("tmu0", -1, P_CLK, HWBLK_TMU0, 0), |
160 | MSTP("cmt0", &r_clk, MSTPCR0, 14, 0, 0, 0), | 163 | SH_HWBLK_CLK("cmt0", -1, R_CLK, HWBLK_CMT, 0), |
161 | MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0, 0, 0), | 164 | SH_HWBLK_CLK("rwdt0", -1, R_CLK, HWBLK_RWDT, 0), |
162 | MSTP("dmac1", &div4_clks[DIV4_B], MSTPCR0, 12, 0, 1, 1), | 165 | SH_HWBLK_CLK("dmac1", -1, B_CLK, HWBLK_DMAC1, 0), |
163 | MSTP("tmu1", &div4_clks[DIV4_P], MSTPCR0, 11, 0, 1, 0), | 166 | SH_HWBLK_CLK("tmu1", -1, P_CLK, HWBLK_TMU1, 0), |
164 | MSTP("flctl0", &div4_clks[DIV4_P], MSTPCR0, 10, 0, 1, 0), | 167 | SH_HWBLK_CLK("flctl0", -1, P_CLK, HWBLK_FLCTL, 0), |
165 | MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 9, 0, 1, 0), | 168 | SH_HWBLK_CLK("scif0", -1, P_CLK, HWBLK_SCIF0, 0), |
166 | MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 8, 0, 1, 0), | 169 | SH_HWBLK_CLK("scif1", -1, P_CLK, HWBLK_SCIF1, 0), |
167 | MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 7, 0, 1, 0), | 170 | SH_HWBLK_CLK("scif2", -1, P_CLK, HWBLK_SCIF2, 0), |
168 | MSTP("scif3", &div4_clks[DIV4_B], MSTPCR0, 6, 0, 1, 0), | 171 | SH_HWBLK_CLK("scif3", -1, B_CLK, HWBLK_SCIF3, 0), |
169 | MSTP("scif4", &div4_clks[DIV4_B], MSTPCR0, 5, 0, 1, 0), | 172 | SH_HWBLK_CLK("scif4", -1, B_CLK, HWBLK_SCIF4, 0), |
170 | MSTP("scif5", &div4_clks[DIV4_B], MSTPCR0, 4, 0, 1, 0), | 173 | SH_HWBLK_CLK("scif5", -1, B_CLK, HWBLK_SCIF5, 0), |
171 | MSTP("msiof0", &div4_clks[DIV4_B], MSTPCR0, 2, 0, 1, 0), | 174 | SH_HWBLK_CLK("msiof0", -1, B_CLK, HWBLK_MSIOF0, 0), |
172 | MSTP("msiof1", &div4_clks[DIV4_B], MSTPCR0, 1, 0, 1, 0), | 175 | SH_HWBLK_CLK("msiof1", -1, B_CLK, HWBLK_MSIOF1, 0), |
173 | MSTP("meram0", &div4_clks[DIV4_SH], MSTPCR0, 0, 1, 1, 0), | 176 | SH_HWBLK_CLK("meram0", -1, SH_CLK, HWBLK_MERAM, 0), |
174 | 177 | ||
175 | MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0, 1, 0), | 178 | SH_HWBLK_CLK("i2c0", -1, P_CLK, HWBLK_IIC, 0), |
176 | MSTP("rtc0", &r_clk, MSTPCR1, 8, 0, 0, 0), | 179 | SH_HWBLK_CLK("rtc0", -1, R_CLK, HWBLK_RTC, 0), |
177 | 180 | ||
178 | MSTP("atapi0", &div4_clks[DIV4_SH], MSTPCR2, 28, 0, 1, 0), | 181 | SH_HWBLK_CLK("atapi0", -1, SH_CLK, HWBLK_ATAPI, 0), |
179 | MSTP("adc0", &div4_clks[DIV4_P], MSTPCR2, 27, 0, 1, 0), | 182 | SH_HWBLK_CLK("adc0", -1, P_CLK, HWBLK_ADC, 0), |
180 | MSTP("tpu0", &div4_clks[DIV4_B], MSTPCR2, 25, 0, 1, 0), | 183 | SH_HWBLK_CLK("tpu0", -1, B_CLK, HWBLK_TPU, 0), |
181 | MSTP("irda0", &div4_clks[DIV4_P], MSTPCR2, 24, 0, 1, 0), | 184 | SH_HWBLK_CLK("irda0", -1, P_CLK, HWBLK_IRDA, 0), |
182 | MSTP("tsif0", &div4_clks[DIV4_B], MSTPCR2, 22, 0, 1, 0), | 185 | SH_HWBLK_CLK("tsif0", -1, B_CLK, HWBLK_TSIF, 0), |
183 | MSTP("icb0", &div4_clks[DIV4_B], MSTPCR2, 21, 0, 1, 1), | 186 | SH_HWBLK_CLK("icb0", -1, B_CLK, HWBLK_ICB, CLK_ENABLE_ON_INIT), |
184 | MSTP("sdhi0", &div4_clks[DIV4_B], MSTPCR2, 18, 0, 1, 0), | 187 | SH_HWBLK_CLK("sdhi0", -1, B_CLK, HWBLK_SDHI0, 0), |
185 | MSTP("sdhi1", &div4_clks[DIV4_B], MSTPCR2, 17, 0, 1, 0), | 188 | SH_HWBLK_CLK("sdhi1", -1, B_CLK, HWBLK_SDHI1, 0), |
186 | MSTP("keysc0", &r_clk, MSTPCR2, 14, 0, 0, 0), | 189 | SH_HWBLK_CLK("keysc0", -1, R_CLK, HWBLK_KEYSC, 0), |
187 | MSTP("usb0", &div4_clks[DIV4_B], MSTPCR2, 11, 0, 1, 0), | 190 | SH_HWBLK_CLK("usb0", -1, B_CLK, HWBLK_USB, 0), |
188 | MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 10, 0, 1, 1), | 191 | SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0), |
189 | MSTP("siu0", &div4_clks[DIV4_B], MSTPCR2, 8, 0, 1, 0), | 192 | SH_HWBLK_CLK("siu0", -1, B_CLK, HWBLK_SIU, 0), |
190 | MSTP("veu1", &div4_clks[DIV4_B], MSTPCR2, 6, 1, 1, 1), | 193 | SH_HWBLK_CLK("veu1", -1, B_CLK, HWBLK_VEU2H1, CLK_ENABLE_ON_INIT), |
191 | MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0, 1, 1), | 194 | SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0), |
192 | MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0, 1, 1), | 195 | SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU, 0), |
193 | MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0, 1, 1), | 196 | SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU, 0), |
194 | MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, 1, 1, 1), | 197 | SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU2H0, CLK_ENABLE_ON_INIT), |
195 | MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, 1, 1, 1), | 198 | SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT), |
196 | MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0, 1, 1), | 199 | SH_HWBLK_CLK("lcdc0", -1, B_CLK, HWBLK_LCDC, 0), |
197 | }; | 200 | }; |
198 | 201 | ||
199 | int __init arch_clk_init(void) | 202 | int __init arch_clk_init(void) |
@@ -216,7 +219,7 @@ int __init arch_clk_init(void) | |||
216 | ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks)); | 219 | ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks)); |
217 | 220 | ||
218 | if (!ret) | 221 | if (!ret) |
219 | ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks)); | 222 | ret = sh_hwblk_clk_register(mstp_clks, ARRAY_SIZE(mstp_clks)); |
220 | 223 | ||
221 | return ret; | 224 | return ret; |
222 | } | 225 | } |
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c index 5d5c9b952883..34611d97378e 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <asm/clock.h> | 24 | #include <asm/clock.h> |
25 | #include <asm/hwblk.h> | ||
26 | #include <cpu/sh7724.h> | ||
25 | 27 | ||
26 | /* SH7724 registers */ | 28 | /* SH7724 registers */ |
27 | #define FRQCRA 0xa4150000 | 29 | #define FRQCRA 0xa4150000 |
@@ -31,9 +33,6 @@ | |||
31 | #define FCLKBCR 0xa415000c | 33 | #define FCLKBCR 0xa415000c |
32 | #define IRDACLKCR 0xa4150018 | 34 | #define IRDACLKCR 0xa4150018 |
33 | #define PLLCR 0xa4150024 | 35 | #define PLLCR 0xa4150024 |
34 | #define MSTPCR0 0xa4150030 | ||
35 | #define MSTPCR1 0xa4150034 | ||
36 | #define MSTPCR2 0xa4150038 | ||
37 | #define SPUCLKCR 0xa415003c | 36 | #define SPUCLKCR 0xa415003c |
38 | #define FLLFRQ 0xa4150050 | 37 | #define FLLFRQ 0xa4150050 |
39 | #define LSTATS 0xa4150060 | 38 | #define LSTATS 0xa4150060 |
@@ -156,64 +155,67 @@ struct clk div6_clks[] = { | |||
156 | SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, 0), | 155 | SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, 0), |
157 | }; | 156 | }; |
158 | 157 | ||
159 | #define MSTP(_str, _parent, _reg, _bit, _force_on, _need_cpg, _need_ram) \ | 158 | #define R_CLK (&r_clk) |
160 | SH_CLK_MSTP32(_str, -1, _parent, _reg, _bit, _force_on * CLK_ENABLE_ON_INIT) | 159 | #define P_CLK (&div4_clks[DIV4_P]) |
160 | #define B_CLK (&div4_clks[DIV4_B]) | ||
161 | #define I_CLK (&div4_clks[DIV4_I]) | ||
162 | #define SH_CLK (&div4_clks[DIV4_SH]) | ||
161 | 163 | ||
162 | static struct clk mstp_clks[] = { | 164 | static struct clk mstp_clks[] = { |
163 | MSTP("tlb0", &div4_clks[DIV4_I], MSTPCR0, 31, 1, 1, 0), | 165 | SH_HWBLK_CLK("tlb0", -1, I_CLK, HWBLK_TLB, CLK_ENABLE_ON_INIT), |
164 | MSTP("ic0", &div4_clks[DIV4_I], MSTPCR0, 30, 1, 1, 0), | 166 | SH_HWBLK_CLK("ic0", -1, I_CLK, HWBLK_IC, CLK_ENABLE_ON_INIT), |
165 | MSTP("oc0", &div4_clks[DIV4_I], MSTPCR0, 29, 1, 1, 0), | 167 | SH_HWBLK_CLK("oc0", -1, I_CLK, HWBLK_OC, CLK_ENABLE_ON_INIT), |
166 | MSTP("rs0", &div4_clks[DIV4_B], MSTPCR0, 28, 1, 1, 0), | 168 | SH_HWBLK_CLK("rs0", -1, B_CLK, HWBLK_RSMEM, CLK_ENABLE_ON_INIT), |
167 | MSTP("ilmem0", &div4_clks[DIV4_I], MSTPCR0, 27, 1, 1, 0), | 169 | SH_HWBLK_CLK("ilmem0", -1, I_CLK, HWBLK_ILMEM, CLK_ENABLE_ON_INIT), |
168 | MSTP("l2c0", &div4_clks[DIV4_SH], MSTPCR0, 26, 1, 1, 0), | 170 | SH_HWBLK_CLK("l2c0", -1, SH_CLK, HWBLK_L2C, CLK_ENABLE_ON_INIT), |
169 | MSTP("fpu0", &div4_clks[DIV4_I], MSTPCR0, 24, 1, 1, 0), | 171 | SH_HWBLK_CLK("fpu0", -1, I_CLK, HWBLK_FPU, CLK_ENABLE_ON_INIT), |
170 | MSTP("intc0", &div4_clks[DIV4_P], MSTPCR0, 22, 1, 1, 0), | 172 | SH_HWBLK_CLK("intc0", -1, P_CLK, HWBLK_INTC, CLK_ENABLE_ON_INIT), |
171 | MSTP("dmac0", &div4_clks[DIV4_B], MSTPCR0, 21, 0, 1, 1), | 173 | SH_HWBLK_CLK("dmac0", -1, B_CLK, HWBLK_DMAC0, 0), |
172 | MSTP("sh0", &div4_clks[DIV4_SH], MSTPCR0, 20, 0, 1, 0), | 174 | SH_HWBLK_CLK("sh0", -1, SH_CLK, HWBLK_SHYWAY, CLK_ENABLE_ON_INIT), |
173 | MSTP("hudi0", &div4_clks[DIV4_P], MSTPCR0, 19, 0, 1, 0), | 175 | SH_HWBLK_CLK("hudi0", -1, P_CLK, HWBLK_HUDI, 0), |
174 | MSTP("ubc0", &div4_clks[DIV4_I], MSTPCR0, 17, 0, 1, 0), | 176 | SH_HWBLK_CLK("ubc0", -1, I_CLK, HWBLK_UBC, 0), |
175 | MSTP("tmu0", &div4_clks[DIV4_P], MSTPCR0, 15, 0, 1, 0), | 177 | SH_HWBLK_CLK("tmu0", -1, P_CLK, HWBLK_TMU0, 0), |
176 | MSTP("cmt0", &r_clk, MSTPCR0, 14, 0, 0, 0), | 178 | SH_HWBLK_CLK("cmt0", -1, R_CLK, HWBLK_CMT, 0), |
177 | MSTP("rwdt0", &r_clk, MSTPCR0, 13, 0, 0, 0), | 179 | SH_HWBLK_CLK("rwdt0", -1, R_CLK, HWBLK_RWDT, 0), |
178 | MSTP("dmac1", &div4_clks[DIV4_B], MSTPCR0, 12, 0, 1, 1), | 180 | SH_HWBLK_CLK("dmac1", -1, B_CLK, HWBLK_DMAC1, 0), |
179 | MSTP("tmu1", &div4_clks[DIV4_P], MSTPCR0, 10, 0, 1, 0), | 181 | SH_HWBLK_CLK("tmu1", -1, P_CLK, HWBLK_TMU1, 0), |
180 | MSTP("scif0", &div4_clks[DIV4_P], MSTPCR0, 9, 0, 1, 0), | 182 | SH_HWBLK_CLK("scif0", -1, P_CLK, HWBLK_SCIF0, 0), |
181 | MSTP("scif1", &div4_clks[DIV4_P], MSTPCR0, 8, 0, 1, 0), | 183 | SH_HWBLK_CLK("scif1", -1, P_CLK, HWBLK_SCIF1, 0), |
182 | MSTP("scif2", &div4_clks[DIV4_P], MSTPCR0, 7, 0, 1, 0), | 184 | SH_HWBLK_CLK("scif2", -1, P_CLK, HWBLK_SCIF2, 0), |
183 | MSTP("scif3", &div4_clks[DIV4_B], MSTPCR0, 6, 0, 1, 0), | 185 | SH_HWBLK_CLK("scif3", -1, B_CLK, HWBLK_SCIF3, 0), |
184 | MSTP("scif4", &div4_clks[DIV4_B], MSTPCR0, 5, 0, 1, 0), | 186 | SH_HWBLK_CLK("scif4", -1, B_CLK, HWBLK_SCIF4, 0), |
185 | MSTP("scif5", &div4_clks[DIV4_B], MSTPCR0, 4, 0, 1, 0), | 187 | SH_HWBLK_CLK("scif5", -1, B_CLK, HWBLK_SCIF5, 0), |
186 | MSTP("msiof0", &div4_clks[DIV4_B], MSTPCR0, 2, 0, 1, 0), | 188 | SH_HWBLK_CLK("msiof0", -1, B_CLK, HWBLK_MSIOF0, 0), |
187 | MSTP("msiof1", &div4_clks[DIV4_B], MSTPCR0, 1, 0, 1, 0), | 189 | SH_HWBLK_CLK("msiof1", -1, B_CLK, HWBLK_MSIOF1, 0), |
188 | 190 | ||
189 | MSTP("keysc0", &r_clk, MSTPCR1, 12, 0, 0, 0), | 191 | SH_HWBLK_CLK("keysc0", -1, R_CLK, HWBLK_KEYSC, 0), |
190 | MSTP("rtc0", &r_clk, MSTPCR1, 11, 0, 0, 0), | 192 | SH_HWBLK_CLK("rtc0", -1, R_CLK, HWBLK_RTC, 0), |
191 | MSTP("i2c0", &div4_clks[DIV4_P], MSTPCR1, 9, 0, 1, 0), | 193 | SH_HWBLK_CLK("i2c0", -1, P_CLK, HWBLK_IIC0, 0), |
192 | MSTP("i2c1", &div4_clks[DIV4_P], MSTPCR1, 8, 0, 1, 0), | 194 | SH_HWBLK_CLK("i2c1", -1, P_CLK, HWBLK_IIC1, 0), |
193 | 195 | ||
194 | MSTP("mmc0", &div4_clks[DIV4_B], MSTPCR2, 29, 0, 1, 0), | 196 | SH_HWBLK_CLK("mmc0", -1, B_CLK, HWBLK_MMC, 0), |
195 | MSTP("eth0", &div4_clks[DIV4_B], MSTPCR2, 28, 0, 1, 0), | 197 | SH_HWBLK_CLK("eth0", -1, B_CLK, HWBLK_ETHER, 0), |
196 | MSTP("atapi0", &div4_clks[DIV4_B], MSTPCR2, 26, 0, 1, 0), | 198 | SH_HWBLK_CLK("atapi0", -1, B_CLK, HWBLK_ATAPI, 0), |
197 | MSTP("tpu0", &div4_clks[DIV4_B], MSTPCR2, 25, 0, 1, 0), | 199 | SH_HWBLK_CLK("tpu0", -1, B_CLK, HWBLK_TPU, 0), |
198 | MSTP("irda0", &div4_clks[DIV4_P], MSTPCR2, 24, 0, 1, 0), | 200 | SH_HWBLK_CLK("irda0", -1, P_CLK, HWBLK_IRDA, 0), |
199 | MSTP("tsif0", &div4_clks[DIV4_B], MSTPCR2, 22, 0, 1, 0), | 201 | SH_HWBLK_CLK("tsif0", -1, B_CLK, HWBLK_TSIF, 0), |
200 | MSTP("usb1", &div4_clks[DIV4_B], MSTPCR2, 21, 0, 1, 1), | 202 | SH_HWBLK_CLK("usb1", -1, B_CLK, HWBLK_USB1, 0), |
201 | MSTP("usb0", &div4_clks[DIV4_B], MSTPCR2, 20, 0, 1, 1), | 203 | SH_HWBLK_CLK("usb0", -1, B_CLK, HWBLK_USB0, 0), |
202 | MSTP("2dg0", &div4_clks[DIV4_B], MSTPCR2, 19, 0, 1, 1), | 204 | SH_HWBLK_CLK("2dg0", -1, B_CLK, HWBLK_2DG, 0), |
203 | MSTP("sdhi0", &div4_clks[DIV4_B], MSTPCR2, 18, 0, 1, 0), | 205 | SH_HWBLK_CLK("sdhi0", -1, B_CLK, HWBLK_SDHI0, 0), |
204 | MSTP("sdhi1", &div4_clks[DIV4_B], MSTPCR2, 17, 0, 1, 0), | 206 | SH_HWBLK_CLK("sdhi1", -1, B_CLK, HWBLK_SDHI1, 0), |
205 | MSTP("veu1", &div4_clks[DIV4_B], MSTPCR2, 15, 1, 1, 1), | 207 | SH_HWBLK_CLK("veu1", -1, B_CLK, HWBLK_VEU1, CLK_ENABLE_ON_INIT), |
206 | MSTP("ceu1", &div4_clks[DIV4_B], MSTPCR2, 13, 0, 1, 1), | 208 | SH_HWBLK_CLK("ceu1", -1, B_CLK, HWBLK_CEU1, 0), |
207 | MSTP("beu1", &div4_clks[DIV4_B], MSTPCR2, 12, 0, 1, 1), | 209 | SH_HWBLK_CLK("beu1", -1, B_CLK, HWBLK_BEU1, 0), |
208 | MSTP("2ddmac0", &div4_clks[DIV4_SH], MSTPCR2, 10, 0, 1, 1), | 210 | SH_HWBLK_CLK("2ddmac0", -1, SH_CLK, HWBLK_2DDMAC, 0), |
209 | MSTP("spu0", &div4_clks[DIV4_B], MSTPCR2, 9, 0, 1, 0), | 211 | SH_HWBLK_CLK("spu0", -1, B_CLK, HWBLK_SPU, 0), |
210 | MSTP("jpu0", &div4_clks[DIV4_B], MSTPCR2, 6, 1, 1, 1), | 212 | SH_HWBLK_CLK("jpu0", -1, B_CLK, HWBLK_JPU, CLK_ENABLE_ON_INIT), |
211 | MSTP("vou0", &div4_clks[DIV4_B], MSTPCR2, 5, 0, 1, 1), | 213 | SH_HWBLK_CLK("vou0", -1, B_CLK, HWBLK_VOU, 0), |
212 | MSTP("beu0", &div4_clks[DIV4_B], MSTPCR2, 4, 0, 1, 1), | 214 | SH_HWBLK_CLK("beu0", -1, B_CLK, HWBLK_BEU0, 0), |
213 | MSTP("ceu0", &div4_clks[DIV4_B], MSTPCR2, 3, 0, 1, 1), | 215 | SH_HWBLK_CLK("ceu0", -1, B_CLK, HWBLK_CEU0, 0), |
214 | MSTP("veu0", &div4_clks[DIV4_B], MSTPCR2, 2, 1, 1, 1), | 216 | SH_HWBLK_CLK("veu0", -1, B_CLK, HWBLK_VEU0, CLK_ENABLE_ON_INIT), |
215 | MSTP("vpu0", &div4_clks[DIV4_B], MSTPCR2, 1, 1, 1, 1), | 217 | SH_HWBLK_CLK("vpu0", -1, B_CLK, HWBLK_VPU, CLK_ENABLE_ON_INIT), |
216 | MSTP("lcdc0", &div4_clks[DIV4_B], MSTPCR2, 0, 0, 1, 1), | 218 | SH_HWBLK_CLK("lcdc0", -1, B_CLK, HWBLK_LCDC, 0), |
217 | }; | 219 | }; |
218 | 220 | ||
219 | int __init arch_clk_init(void) | 221 | int __init arch_clk_init(void) |
@@ -236,7 +238,7 @@ int __init arch_clk_init(void) | |||
236 | ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks)); | 238 | ret = sh_clk_div6_register(div6_clks, ARRAY_SIZE(div6_clks)); |
237 | 239 | ||
238 | if (!ret) | 240 | if (!ret) |
239 | ret = sh_clk_mstp32_register(mstp_clks, ARRAY_SIZE(mstp_clks)); | 241 | ret = sh_hwblk_clk_register(mstp_clks, ARRAY_SIZE(mstp_clks)); |
240 | 242 | ||
241 | return ret; | 243 | return ret; |
242 | } | 244 | } |
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c new file mode 100644 index 000000000000..a288b5d92341 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh4a/hwblk-sh7722.c | ||
3 | * | ||
4 | * SH7722 hardware block support | ||
5 | * | ||
6 | * Copyright (C) 2009 Magnus Damm | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <asm/suspend.h> | ||
25 | #include <asm/hwblk.h> | ||
26 | #include <cpu/sh7722.h> | ||
27 | |||
28 | /* SH7722 registers */ | ||
29 | #define MSTPCR0 0xa4150030 | ||
30 | #define MSTPCR1 0xa4150034 | ||
31 | #define MSTPCR2 0xa4150038 | ||
32 | |||
33 | /* SH7722 Power Domains */ | ||
34 | enum { CORE_AREA, SUB_AREA, CORE_AREA_BM }; | ||
35 | static struct hwblk_area sh7722_hwblk_area[] = { | ||
36 | [CORE_AREA] = HWBLK_AREA(0, 0), | ||
37 | [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA), | ||
38 | [SUB_AREA] = HWBLK_AREA(0, 0), | ||
39 | }; | ||
40 | |||
41 | /* Table mapping HWBLK to Module Stop Bit and Power Domain */ | ||
42 | static struct hwblk sh7722_hwblk[HWBLK_NR] = { | ||
43 | [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA), | ||
44 | [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA), | ||
45 | [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA), | ||
46 | [HWBLK_URAM] = HWBLK(MSTPCR0, 28, CORE_AREA), | ||
47 | [HWBLK_XYMEM] = HWBLK(MSTPCR0, 26, CORE_AREA), | ||
48 | [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA), | ||
49 | [HWBLK_DMAC] = HWBLK(MSTPCR0, 21, CORE_AREA_BM), | ||
50 | [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA), | ||
51 | [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA), | ||
52 | [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA), | ||
53 | [HWBLK_TMU] = HWBLK(MSTPCR0, 15, CORE_AREA), | ||
54 | [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA), | ||
55 | [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA), | ||
56 | [HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA), | ||
57 | [HWBLK_SCIF0] = HWBLK(MSTPCR0, 7, CORE_AREA), | ||
58 | [HWBLK_SCIF1] = HWBLK(MSTPCR0, 6, CORE_AREA), | ||
59 | [HWBLK_SCIF2] = HWBLK(MSTPCR0, 5, CORE_AREA), | ||
60 | [HWBLK_SIO] = HWBLK(MSTPCR0, 3, CORE_AREA), | ||
61 | [HWBLK_SIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA), | ||
62 | [HWBLK_SIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA), | ||
63 | |||
64 | [HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA), | ||
65 | [HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA), | ||
66 | |||
67 | [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA), | ||
68 | [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA), | ||
69 | [HWBLK_SDHI] = HWBLK(MSTPCR2, 18, CORE_AREA), | ||
70 | [HWBLK_SIM] = HWBLK(MSTPCR2, 16, CORE_AREA), | ||
71 | [HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA), | ||
72 | [HWBLK_TSIF] = HWBLK(MSTPCR2, 13, SUB_AREA), | ||
73 | [HWBLK_USBF] = HWBLK(MSTPCR2, 11, CORE_AREA), | ||
74 | [HWBLK_2DG] = HWBLK(MSTPCR2, 9, CORE_AREA_BM), | ||
75 | [HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA), | ||
76 | [HWBLK_JPU] = HWBLK(MSTPCR2, 6, CORE_AREA_BM), | ||
77 | [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM), | ||
78 | [HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM), | ||
79 | [HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM), | ||
80 | [HWBLK_VEU] = HWBLK(MSTPCR2, 2, CORE_AREA_BM), | ||
81 | [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM), | ||
82 | [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM), | ||
83 | }; | ||
84 | |||
85 | static struct hwblk_info sh7722_hwblk_info = { | ||
86 | .areas = sh7722_hwblk_area, | ||
87 | .nr_areas = ARRAY_SIZE(sh7722_hwblk_area), | ||
88 | .hwblks = sh7722_hwblk, | ||
89 | .nr_hwblks = ARRAY_SIZE(sh7722_hwblk), | ||
90 | }; | ||
91 | |||
92 | int arch_hwblk_sleep_mode(void) | ||
93 | { | ||
94 | if (!sh7722_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE]) | ||
95 | return SUSP_SH_STANDBY | SUSP_SH_SF; | ||
96 | |||
97 | if (!sh7722_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE]) | ||
98 | return SUSP_SH_SLEEP | SUSP_SH_SF; | ||
99 | |||
100 | return SUSP_SH_SLEEP; | ||
101 | } | ||
102 | |||
103 | int __init arch_hwblk_init(void) | ||
104 | { | ||
105 | return hwblk_register(&sh7722_hwblk_info); | ||
106 | } | ||
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c new file mode 100644 index 000000000000..a7f4684d2032 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh4a/hwblk-sh7723.c | ||
3 | * | ||
4 | * SH7723 hardware block support | ||
5 | * | ||
6 | * Copyright (C) 2009 Magnus Damm | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <asm/suspend.h> | ||
25 | #include <asm/hwblk.h> | ||
26 | #include <cpu/sh7723.h> | ||
27 | |||
28 | /* SH7723 registers */ | ||
29 | #define MSTPCR0 0xa4150030 | ||
30 | #define MSTPCR1 0xa4150034 | ||
31 | #define MSTPCR2 0xa4150038 | ||
32 | |||
33 | /* SH7723 Power Domains */ | ||
34 | enum { CORE_AREA, SUB_AREA, CORE_AREA_BM }; | ||
35 | static struct hwblk_area sh7723_hwblk_area[] = { | ||
36 | [CORE_AREA] = HWBLK_AREA(0, 0), | ||
37 | [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA), | ||
38 | [SUB_AREA] = HWBLK_AREA(0, 0), | ||
39 | }; | ||
40 | |||
41 | /* Table mapping HWBLK to Module Stop Bit and Power Domain */ | ||
42 | static struct hwblk sh7723_hwblk[HWBLK_NR] = { | ||
43 | [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA), | ||
44 | [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA), | ||
45 | [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA), | ||
46 | [HWBLK_L2C] = HWBLK(MSTPCR0, 28, CORE_AREA), | ||
47 | [HWBLK_ILMEM] = HWBLK(MSTPCR0, 27, CORE_AREA), | ||
48 | [HWBLK_FPU] = HWBLK(MSTPCR0, 24, CORE_AREA), | ||
49 | [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA), | ||
50 | [HWBLK_DMAC0] = HWBLK(MSTPCR0, 21, CORE_AREA_BM), | ||
51 | [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA), | ||
52 | [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA), | ||
53 | [HWBLK_DBG] = HWBLK(MSTPCR0, 18, CORE_AREA), | ||
54 | [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA), | ||
55 | [HWBLK_SUBC] = HWBLK(MSTPCR0, 16, CORE_AREA), | ||
56 | [HWBLK_TMU0] = HWBLK(MSTPCR0, 15, CORE_AREA), | ||
57 | [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA), | ||
58 | [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA), | ||
59 | [HWBLK_DMAC1] = HWBLK(MSTPCR0, 12, CORE_AREA_BM), | ||
60 | [HWBLK_TMU1] = HWBLK(MSTPCR0, 11, CORE_AREA), | ||
61 | [HWBLK_FLCTL] = HWBLK(MSTPCR0, 10, CORE_AREA), | ||
62 | [HWBLK_SCIF0] = HWBLK(MSTPCR0, 9, CORE_AREA), | ||
63 | [HWBLK_SCIF1] = HWBLK(MSTPCR0, 8, CORE_AREA), | ||
64 | [HWBLK_SCIF2] = HWBLK(MSTPCR0, 7, CORE_AREA), | ||
65 | [HWBLK_SCIF3] = HWBLK(MSTPCR0, 6, CORE_AREA), | ||
66 | [HWBLK_SCIF4] = HWBLK(MSTPCR0, 5, CORE_AREA), | ||
67 | [HWBLK_SCIF5] = HWBLK(MSTPCR0, 4, CORE_AREA), | ||
68 | [HWBLK_MSIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA), | ||
69 | [HWBLK_MSIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA), | ||
70 | [HWBLK_MERAM] = HWBLK(MSTPCR0, 0, CORE_AREA), | ||
71 | |||
72 | [HWBLK_IIC] = HWBLK(MSTPCR1, 9, CORE_AREA), | ||
73 | [HWBLK_RTC] = HWBLK(MSTPCR1, 8, SUB_AREA), | ||
74 | |||
75 | [HWBLK_ATAPI] = HWBLK(MSTPCR2, 28, CORE_AREA_BM), | ||
76 | [HWBLK_ADC] = HWBLK(MSTPCR2, 27, CORE_AREA), | ||
77 | [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA), | ||
78 | [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA), | ||
79 | [HWBLK_TSIF] = HWBLK(MSTPCR2, 22, CORE_AREA), | ||
80 | [HWBLK_ICB] = HWBLK(MSTPCR2, 21, CORE_AREA_BM), | ||
81 | [HWBLK_SDHI0] = HWBLK(MSTPCR2, 18, CORE_AREA), | ||
82 | [HWBLK_SDHI1] = HWBLK(MSTPCR2, 17, CORE_AREA), | ||
83 | [HWBLK_KEYSC] = HWBLK(MSTPCR2, 14, SUB_AREA), | ||
84 | [HWBLK_USB] = HWBLK(MSTPCR2, 11, CORE_AREA), | ||
85 | [HWBLK_2DG] = HWBLK(MSTPCR2, 10, CORE_AREA_BM), | ||
86 | [HWBLK_SIU] = HWBLK(MSTPCR2, 8, CORE_AREA), | ||
87 | [HWBLK_VEU2H1] = HWBLK(MSTPCR2, 6, CORE_AREA_BM), | ||
88 | [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM), | ||
89 | [HWBLK_BEU] = HWBLK(MSTPCR2, 4, CORE_AREA_BM), | ||
90 | [HWBLK_CEU] = HWBLK(MSTPCR2, 3, CORE_AREA_BM), | ||
91 | [HWBLK_VEU2H0] = HWBLK(MSTPCR2, 2, CORE_AREA_BM), | ||
92 | [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM), | ||
93 | [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM), | ||
94 | }; | ||
95 | |||
96 | static struct hwblk_info sh7723_hwblk_info = { | ||
97 | .areas = sh7723_hwblk_area, | ||
98 | .nr_areas = ARRAY_SIZE(sh7723_hwblk_area), | ||
99 | .hwblks = sh7723_hwblk, | ||
100 | .nr_hwblks = ARRAY_SIZE(sh7723_hwblk), | ||
101 | }; | ||
102 | |||
103 | int arch_hwblk_sleep_mode(void) | ||
104 | { | ||
105 | if (!sh7723_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE]) | ||
106 | return SUSP_SH_STANDBY | SUSP_SH_SF; | ||
107 | |||
108 | if (!sh7723_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE]) | ||
109 | return SUSP_SH_SLEEP | SUSP_SH_SF; | ||
110 | |||
111 | return SUSP_SH_SLEEP; | ||
112 | } | ||
113 | |||
114 | int __init arch_hwblk_init(void) | ||
115 | { | ||
116 | return hwblk_register(&sh7723_hwblk_info); | ||
117 | } | ||
diff --git a/arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c b/arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c new file mode 100644 index 000000000000..1613ad6013c3 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/sh4a/hwblk-sh7724.c | ||
3 | * | ||
4 | * SH7724 hardware block support | ||
5 | * | ||
6 | * Copyright (C) 2009 Magnus Damm | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <asm/suspend.h> | ||
25 | #include <asm/hwblk.h> | ||
26 | #include <cpu/sh7724.h> | ||
27 | |||
28 | /* SH7724 registers */ | ||
29 | #define MSTPCR0 0xa4150030 | ||
30 | #define MSTPCR1 0xa4150034 | ||
31 | #define MSTPCR2 0xa4150038 | ||
32 | |||
33 | /* SH7724 Power Domains */ | ||
34 | enum { CORE_AREA, SUB_AREA, CORE_AREA_BM }; | ||
35 | static struct hwblk_area sh7724_hwblk_area[] = { | ||
36 | [CORE_AREA] = HWBLK_AREA(0, 0), | ||
37 | [CORE_AREA_BM] = HWBLK_AREA(HWBLK_AREA_FLAG_PARENT, CORE_AREA), | ||
38 | [SUB_AREA] = HWBLK_AREA(0, 0), | ||
39 | }; | ||
40 | |||
41 | /* Table mapping HWBLK to Module Stop Bit and Power Domain */ | ||
42 | static struct hwblk sh7724_hwblk[HWBLK_NR] = { | ||
43 | [HWBLK_TLB] = HWBLK(MSTPCR0, 31, CORE_AREA), | ||
44 | [HWBLK_IC] = HWBLK(MSTPCR0, 30, CORE_AREA), | ||
45 | [HWBLK_OC] = HWBLK(MSTPCR0, 29, CORE_AREA), | ||
46 | [HWBLK_RSMEM] = HWBLK(MSTPCR0, 28, CORE_AREA), | ||
47 | [HWBLK_ILMEM] = HWBLK(MSTPCR0, 27, CORE_AREA), | ||
48 | [HWBLK_L2C] = HWBLK(MSTPCR0, 26, CORE_AREA), | ||
49 | [HWBLK_FPU] = HWBLK(MSTPCR0, 24, CORE_AREA), | ||
50 | [HWBLK_INTC] = HWBLK(MSTPCR0, 22, CORE_AREA), | ||
51 | [HWBLK_DMAC0] = HWBLK(MSTPCR0, 21, CORE_AREA_BM), | ||
52 | [HWBLK_SHYWAY] = HWBLK(MSTPCR0, 20, CORE_AREA), | ||
53 | [HWBLK_HUDI] = HWBLK(MSTPCR0, 19, CORE_AREA), | ||
54 | [HWBLK_DBG] = HWBLK(MSTPCR0, 18, CORE_AREA), | ||
55 | [HWBLK_UBC] = HWBLK(MSTPCR0, 17, CORE_AREA), | ||
56 | [HWBLK_TMU0] = HWBLK(MSTPCR0, 15, CORE_AREA), | ||
57 | [HWBLK_CMT] = HWBLK(MSTPCR0, 14, SUB_AREA), | ||
58 | [HWBLK_RWDT] = HWBLK(MSTPCR0, 13, SUB_AREA), | ||
59 | [HWBLK_DMAC1] = HWBLK(MSTPCR0, 12, CORE_AREA_BM), | ||
60 | [HWBLK_TMU1] = HWBLK(MSTPCR0, 10, CORE_AREA), | ||
61 | [HWBLK_SCIF0] = HWBLK(MSTPCR0, 9, CORE_AREA), | ||
62 | [HWBLK_SCIF1] = HWBLK(MSTPCR0, 8, CORE_AREA), | ||
63 | [HWBLK_SCIF2] = HWBLK(MSTPCR0, 7, CORE_AREA), | ||
64 | [HWBLK_SCIF3] = HWBLK(MSTPCR0, 6, CORE_AREA), | ||
65 | [HWBLK_SCIF4] = HWBLK(MSTPCR0, 5, CORE_AREA), | ||
66 | [HWBLK_SCIF5] = HWBLK(MSTPCR0, 4, CORE_AREA), | ||
67 | [HWBLK_MSIOF0] = HWBLK(MSTPCR0, 2, CORE_AREA), | ||
68 | [HWBLK_MSIOF1] = HWBLK(MSTPCR0, 1, CORE_AREA), | ||
69 | |||
70 | [HWBLK_KEYSC] = HWBLK(MSTPCR1, 12, SUB_AREA), | ||
71 | [HWBLK_RTC] = HWBLK(MSTPCR1, 11, SUB_AREA), | ||
72 | [HWBLK_IIC0] = HWBLK(MSTPCR1, 9, CORE_AREA), | ||
73 | [HWBLK_IIC1] = HWBLK(MSTPCR1, 8, CORE_AREA), | ||
74 | |||
75 | [HWBLK_MMC] = HWBLK(MSTPCR2, 29, CORE_AREA), | ||
76 | [HWBLK_ETHER] = HWBLK(MSTPCR2, 28, CORE_AREA_BM), | ||
77 | [HWBLK_ATAPI] = HWBLK(MSTPCR2, 26, CORE_AREA_BM), | ||
78 | [HWBLK_TPU] = HWBLK(MSTPCR2, 25, CORE_AREA), | ||
79 | [HWBLK_IRDA] = HWBLK(MSTPCR2, 24, CORE_AREA), | ||
80 | [HWBLK_TSIF] = HWBLK(MSTPCR2, 22, CORE_AREA), | ||
81 | [HWBLK_USB1] = HWBLK(MSTPCR2, 21, CORE_AREA), | ||
82 | [HWBLK_USB0] = HWBLK(MSTPCR2, 20, CORE_AREA), | ||
83 | [HWBLK_2DG] = HWBLK(MSTPCR2, 19, CORE_AREA_BM), | ||
84 | [HWBLK_SDHI0] = HWBLK(MSTPCR2, 18, CORE_AREA), | ||
85 | [HWBLK_SDHI1] = HWBLK(MSTPCR2, 17, CORE_AREA), | ||
86 | [HWBLK_VEU1] = HWBLK(MSTPCR2, 15, CORE_AREA_BM), | ||
87 | [HWBLK_CEU1] = HWBLK(MSTPCR2, 13, CORE_AREA_BM), | ||
88 | [HWBLK_BEU1] = HWBLK(MSTPCR2, 12, CORE_AREA_BM), | ||
89 | [HWBLK_2DDMAC] = HWBLK(MSTPCR2, 10, CORE_AREA_BM), | ||
90 | [HWBLK_SPU] = HWBLK(MSTPCR2, 9, CORE_AREA_BM), | ||
91 | [HWBLK_JPU] = HWBLK(MSTPCR2, 6, CORE_AREA_BM), | ||
92 | [HWBLK_VOU] = HWBLK(MSTPCR2, 5, CORE_AREA_BM), | ||
93 | [HWBLK_BEU0] = HWBLK(MSTPCR2, 4, CORE_AREA_BM), | ||
94 | [HWBLK_CEU0] = HWBLK(MSTPCR2, 3, CORE_AREA_BM), | ||
95 | [HWBLK_VEU0] = HWBLK(MSTPCR2, 2, CORE_AREA_BM), | ||
96 | [HWBLK_VPU] = HWBLK(MSTPCR2, 1, CORE_AREA_BM), | ||
97 | [HWBLK_LCDC] = HWBLK(MSTPCR2, 0, CORE_AREA_BM), | ||
98 | }; | ||
99 | |||
100 | static struct hwblk_info sh7724_hwblk_info = { | ||
101 | .areas = sh7724_hwblk_area, | ||
102 | .nr_areas = ARRAY_SIZE(sh7724_hwblk_area), | ||
103 | .hwblks = sh7724_hwblk, | ||
104 | .nr_hwblks = ARRAY_SIZE(sh7724_hwblk), | ||
105 | }; | ||
106 | |||
107 | int arch_hwblk_sleep_mode(void) | ||
108 | { | ||
109 | if (!sh7724_hwblk_area[CORE_AREA].cnt[HWBLK_CNT_USAGE]) | ||
110 | return SUSP_SH_STANDBY | SUSP_SH_SF; | ||
111 | |||
112 | if (!sh7724_hwblk_area[CORE_AREA_BM].cnt[HWBLK_CNT_USAGE]) | ||
113 | return SUSP_SH_SLEEP | SUSP_SH_SF; | ||
114 | |||
115 | return SUSP_SH_SLEEP; | ||
116 | } | ||
117 | |||
118 | int __init arch_hwblk_init(void) | ||
119 | { | ||
120 | return hwblk_register(&sh7724_hwblk_info); | ||
121 | } | ||
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c index 1a956b1beccc..4a9010bf4fd3 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c | |||
@@ -40,7 +40,7 @@ static struct platform_device iic_device = { | |||
40 | }; | 40 | }; |
41 | 41 | ||
42 | static struct r8a66597_platdata r8a66597_data = { | 42 | static struct r8a66597_platdata r8a66597_data = { |
43 | /* This set zero to all members */ | 43 | .on_chip = 1, |
44 | }; | 44 | }; |
45 | 45 | ||
46 | static struct resource usb_host_resources[] = { | 46 | static struct resource usb_host_resources[] = { |
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c index cda76ebf87c3..35097753456c 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7722.c | |||
@@ -13,9 +13,11 @@ | |||
13 | #include <linux/serial_sci.h> | 13 | #include <linux/serial_sci.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/uio_driver.h> | 15 | #include <linux/uio_driver.h> |
16 | #include <linux/usb/m66592.h> | ||
16 | #include <linux/sh_timer.h> | 17 | #include <linux/sh_timer.h> |
17 | #include <asm/clock.h> | 18 | #include <asm/clock.h> |
18 | #include <asm/mmzone.h> | 19 | #include <asm/mmzone.h> |
20 | #include <cpu/sh7722.h> | ||
19 | 21 | ||
20 | static struct resource rtc_resources[] = { | 22 | static struct resource rtc_resources[] = { |
21 | [0] = { | 23 | [0] = { |
@@ -45,11 +47,18 @@ static struct platform_device rtc_device = { | |||
45 | .id = -1, | 47 | .id = -1, |
46 | .num_resources = ARRAY_SIZE(rtc_resources), | 48 | .num_resources = ARRAY_SIZE(rtc_resources), |
47 | .resource = rtc_resources, | 49 | .resource = rtc_resources, |
50 | .archdata = { | ||
51 | .hwblk_id = HWBLK_RTC, | ||
52 | }, | ||
53 | }; | ||
54 | |||
55 | static struct m66592_platdata usbf_platdata = { | ||
56 | .on_chip = 1, | ||
48 | }; | 57 | }; |
49 | 58 | ||
50 | static struct resource usbf_resources[] = { | 59 | static struct resource usbf_resources[] = { |
51 | [0] = { | 60 | [0] = { |
52 | .name = "m66592_udc", | 61 | .name = "USBF", |
53 | .start = 0x04480000, | 62 | .start = 0x04480000, |
54 | .end = 0x044800FF, | 63 | .end = 0x044800FF, |
55 | .flags = IORESOURCE_MEM, | 64 | .flags = IORESOURCE_MEM, |
@@ -67,9 +76,13 @@ static struct platform_device usbf_device = { | |||
67 | .dev = { | 76 | .dev = { |
68 | .dma_mask = NULL, | 77 | .dma_mask = NULL, |
69 | .coherent_dma_mask = 0xffffffff, | 78 | .coherent_dma_mask = 0xffffffff, |
79 | .platform_data = &usbf_platdata, | ||
70 | }, | 80 | }, |
71 | .num_resources = ARRAY_SIZE(usbf_resources), | 81 | .num_resources = ARRAY_SIZE(usbf_resources), |
72 | .resource = usbf_resources, | 82 | .resource = usbf_resources, |
83 | .archdata = { | ||
84 | .hwblk_id = HWBLK_USBF, | ||
85 | }, | ||
73 | }; | 86 | }; |
74 | 87 | ||
75 | static struct resource iic_resources[] = { | 88 | static struct resource iic_resources[] = { |
@@ -91,6 +104,9 @@ static struct platform_device iic_device = { | |||
91 | .id = 0, /* "i2c0" clock */ | 104 | .id = 0, /* "i2c0" clock */ |
92 | .num_resources = ARRAY_SIZE(iic_resources), | 105 | .num_resources = ARRAY_SIZE(iic_resources), |
93 | .resource = iic_resources, | 106 | .resource = iic_resources, |
107 | .archdata = { | ||
108 | .hwblk_id = HWBLK_IIC, | ||
109 | }, | ||
94 | }; | 110 | }; |
95 | 111 | ||
96 | static struct uio_info vpu_platform_data = { | 112 | static struct uio_info vpu_platform_data = { |
@@ -119,6 +135,9 @@ static struct platform_device vpu_device = { | |||
119 | }, | 135 | }, |
120 | .resource = vpu_resources, | 136 | .resource = vpu_resources, |
121 | .num_resources = ARRAY_SIZE(vpu_resources), | 137 | .num_resources = ARRAY_SIZE(vpu_resources), |
138 | .archdata = { | ||
139 | .hwblk_id = HWBLK_VPU, | ||
140 | }, | ||
122 | }; | 141 | }; |
123 | 142 | ||
124 | static struct uio_info veu_platform_data = { | 143 | static struct uio_info veu_platform_data = { |
@@ -147,6 +166,9 @@ static struct platform_device veu_device = { | |||
147 | }, | 166 | }, |
148 | .resource = veu_resources, | 167 | .resource = veu_resources, |
149 | .num_resources = ARRAY_SIZE(veu_resources), | 168 | .num_resources = ARRAY_SIZE(veu_resources), |
169 | .archdata = { | ||
170 | .hwblk_id = HWBLK_VEU, | ||
171 | }, | ||
150 | }; | 172 | }; |
151 | 173 | ||
152 | static struct uio_info jpu_platform_data = { | 174 | static struct uio_info jpu_platform_data = { |
@@ -175,6 +197,9 @@ static struct platform_device jpu_device = { | |||
175 | }, | 197 | }, |
176 | .resource = jpu_resources, | 198 | .resource = jpu_resources, |
177 | .num_resources = ARRAY_SIZE(jpu_resources), | 199 | .num_resources = ARRAY_SIZE(jpu_resources), |
200 | .archdata = { | ||
201 | .hwblk_id = HWBLK_JPU, | ||
202 | }, | ||
178 | }; | 203 | }; |
179 | 204 | ||
180 | static struct sh_timer_config cmt_platform_data = { | 205 | static struct sh_timer_config cmt_platform_data = { |
@@ -207,6 +232,9 @@ static struct platform_device cmt_device = { | |||
207 | }, | 232 | }, |
208 | .resource = cmt_resources, | 233 | .resource = cmt_resources, |
209 | .num_resources = ARRAY_SIZE(cmt_resources), | 234 | .num_resources = ARRAY_SIZE(cmt_resources), |
235 | .archdata = { | ||
236 | .hwblk_id = HWBLK_CMT, | ||
237 | }, | ||
210 | }; | 238 | }; |
211 | 239 | ||
212 | static struct sh_timer_config tmu0_platform_data = { | 240 | static struct sh_timer_config tmu0_platform_data = { |
@@ -238,6 +266,9 @@ static struct platform_device tmu0_device = { | |||
238 | }, | 266 | }, |
239 | .resource = tmu0_resources, | 267 | .resource = tmu0_resources, |
240 | .num_resources = ARRAY_SIZE(tmu0_resources), | 268 | .num_resources = ARRAY_SIZE(tmu0_resources), |
269 | .archdata = { | ||
270 | .hwblk_id = HWBLK_TMU, | ||
271 | }, | ||
241 | }; | 272 | }; |
242 | 273 | ||
243 | static struct sh_timer_config tmu1_platform_data = { | 274 | static struct sh_timer_config tmu1_platform_data = { |
@@ -269,6 +300,9 @@ static struct platform_device tmu1_device = { | |||
269 | }, | 300 | }, |
270 | .resource = tmu1_resources, | 301 | .resource = tmu1_resources, |
271 | .num_resources = ARRAY_SIZE(tmu1_resources), | 302 | .num_resources = ARRAY_SIZE(tmu1_resources), |
303 | .archdata = { | ||
304 | .hwblk_id = HWBLK_TMU, | ||
305 | }, | ||
272 | }; | 306 | }; |
273 | 307 | ||
274 | static struct sh_timer_config tmu2_platform_data = { | 308 | static struct sh_timer_config tmu2_platform_data = { |
@@ -299,6 +333,9 @@ static struct platform_device tmu2_device = { | |||
299 | }, | 333 | }, |
300 | .resource = tmu2_resources, | 334 | .resource = tmu2_resources, |
301 | .num_resources = ARRAY_SIZE(tmu2_resources), | 335 | .num_resources = ARRAY_SIZE(tmu2_resources), |
336 | .archdata = { | ||
337 | .hwblk_id = HWBLK_TMU, | ||
338 | }, | ||
302 | }; | 339 | }; |
303 | 340 | ||
304 | static struct plat_sci_port sci_platform_data[] = { | 341 | static struct plat_sci_port sci_platform_data[] = { |
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c index b45dace9539f..4caa5a7ca86e 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7723.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7723.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <asm/clock.h> | 19 | #include <asm/clock.h> |
20 | #include <asm/mmzone.h> | 20 | #include <asm/mmzone.h> |
21 | #include <cpu/sh7723.h> | ||
21 | 22 | ||
22 | static struct uio_info vpu_platform_data = { | 23 | static struct uio_info vpu_platform_data = { |
23 | .name = "VPU5", | 24 | .name = "VPU5", |
@@ -45,6 +46,9 @@ static struct platform_device vpu_device = { | |||
45 | }, | 46 | }, |
46 | .resource = vpu_resources, | 47 | .resource = vpu_resources, |
47 | .num_resources = ARRAY_SIZE(vpu_resources), | 48 | .num_resources = ARRAY_SIZE(vpu_resources), |
49 | .archdata = { | ||
50 | .hwblk_id = HWBLK_VPU, | ||
51 | }, | ||
48 | }; | 52 | }; |
49 | 53 | ||
50 | static struct uio_info veu0_platform_data = { | 54 | static struct uio_info veu0_platform_data = { |
@@ -73,6 +77,9 @@ static struct platform_device veu0_device = { | |||
73 | }, | 77 | }, |
74 | .resource = veu0_resources, | 78 | .resource = veu0_resources, |
75 | .num_resources = ARRAY_SIZE(veu0_resources), | 79 | .num_resources = ARRAY_SIZE(veu0_resources), |
80 | .archdata = { | ||
81 | .hwblk_id = HWBLK_VEU2H0, | ||
82 | }, | ||
76 | }; | 83 | }; |
77 | 84 | ||
78 | static struct uio_info veu1_platform_data = { | 85 | static struct uio_info veu1_platform_data = { |
@@ -101,6 +108,9 @@ static struct platform_device veu1_device = { | |||
101 | }, | 108 | }, |
102 | .resource = veu1_resources, | 109 | .resource = veu1_resources, |
103 | .num_resources = ARRAY_SIZE(veu1_resources), | 110 | .num_resources = ARRAY_SIZE(veu1_resources), |
111 | .archdata = { | ||
112 | .hwblk_id = HWBLK_VEU2H1, | ||
113 | }, | ||
104 | }; | 114 | }; |
105 | 115 | ||
106 | static struct sh_timer_config cmt_platform_data = { | 116 | static struct sh_timer_config cmt_platform_data = { |
@@ -133,6 +143,9 @@ static struct platform_device cmt_device = { | |||
133 | }, | 143 | }, |
134 | .resource = cmt_resources, | 144 | .resource = cmt_resources, |
135 | .num_resources = ARRAY_SIZE(cmt_resources), | 145 | .num_resources = ARRAY_SIZE(cmt_resources), |
146 | .archdata = { | ||
147 | .hwblk_id = HWBLK_CMT, | ||
148 | }, | ||
136 | }; | 149 | }; |
137 | 150 | ||
138 | static struct sh_timer_config tmu0_platform_data = { | 151 | static struct sh_timer_config tmu0_platform_data = { |
@@ -164,6 +177,9 @@ static struct platform_device tmu0_device = { | |||
164 | }, | 177 | }, |
165 | .resource = tmu0_resources, | 178 | .resource = tmu0_resources, |
166 | .num_resources = ARRAY_SIZE(tmu0_resources), | 179 | .num_resources = ARRAY_SIZE(tmu0_resources), |
180 | .archdata = { | ||
181 | .hwblk_id = HWBLK_TMU0, | ||
182 | }, | ||
167 | }; | 183 | }; |
168 | 184 | ||
169 | static struct sh_timer_config tmu1_platform_data = { | 185 | static struct sh_timer_config tmu1_platform_data = { |
@@ -195,6 +211,9 @@ static struct platform_device tmu1_device = { | |||
195 | }, | 211 | }, |
196 | .resource = tmu1_resources, | 212 | .resource = tmu1_resources, |
197 | .num_resources = ARRAY_SIZE(tmu1_resources), | 213 | .num_resources = ARRAY_SIZE(tmu1_resources), |
214 | .archdata = { | ||
215 | .hwblk_id = HWBLK_TMU0, | ||
216 | }, | ||
198 | }; | 217 | }; |
199 | 218 | ||
200 | static struct sh_timer_config tmu2_platform_data = { | 219 | static struct sh_timer_config tmu2_platform_data = { |
@@ -225,6 +244,9 @@ static struct platform_device tmu2_device = { | |||
225 | }, | 244 | }, |
226 | .resource = tmu2_resources, | 245 | .resource = tmu2_resources, |
227 | .num_resources = ARRAY_SIZE(tmu2_resources), | 246 | .num_resources = ARRAY_SIZE(tmu2_resources), |
247 | .archdata = { | ||
248 | .hwblk_id = HWBLK_TMU0, | ||
249 | }, | ||
228 | }; | 250 | }; |
229 | 251 | ||
230 | static struct sh_timer_config tmu3_platform_data = { | 252 | static struct sh_timer_config tmu3_platform_data = { |
@@ -255,6 +277,9 @@ static struct platform_device tmu3_device = { | |||
255 | }, | 277 | }, |
256 | .resource = tmu3_resources, | 278 | .resource = tmu3_resources, |
257 | .num_resources = ARRAY_SIZE(tmu3_resources), | 279 | .num_resources = ARRAY_SIZE(tmu3_resources), |
280 | .archdata = { | ||
281 | .hwblk_id = HWBLK_TMU1, | ||
282 | }, | ||
258 | }; | 283 | }; |
259 | 284 | ||
260 | static struct sh_timer_config tmu4_platform_data = { | 285 | static struct sh_timer_config tmu4_platform_data = { |
@@ -285,6 +310,9 @@ static struct platform_device tmu4_device = { | |||
285 | }, | 310 | }, |
286 | .resource = tmu4_resources, | 311 | .resource = tmu4_resources, |
287 | .num_resources = ARRAY_SIZE(tmu4_resources), | 312 | .num_resources = ARRAY_SIZE(tmu4_resources), |
313 | .archdata = { | ||
314 | .hwblk_id = HWBLK_TMU1, | ||
315 | }, | ||
288 | }; | 316 | }; |
289 | 317 | ||
290 | static struct sh_timer_config tmu5_platform_data = { | 318 | static struct sh_timer_config tmu5_platform_data = { |
@@ -315,6 +343,9 @@ static struct platform_device tmu5_device = { | |||
315 | }, | 343 | }, |
316 | .resource = tmu5_resources, | 344 | .resource = tmu5_resources, |
317 | .num_resources = ARRAY_SIZE(tmu5_resources), | 345 | .num_resources = ARRAY_SIZE(tmu5_resources), |
346 | .archdata = { | ||
347 | .hwblk_id = HWBLK_TMU1, | ||
348 | }, | ||
318 | }; | 349 | }; |
319 | 350 | ||
320 | static struct plat_sci_port sci_platform_data[] = { | 351 | static struct plat_sci_port sci_platform_data[] = { |
@@ -395,10 +426,13 @@ static struct platform_device rtc_device = { | |||
395 | .id = -1, | 426 | .id = -1, |
396 | .num_resources = ARRAY_SIZE(rtc_resources), | 427 | .num_resources = ARRAY_SIZE(rtc_resources), |
397 | .resource = rtc_resources, | 428 | .resource = rtc_resources, |
429 | .archdata = { | ||
430 | .hwblk_id = HWBLK_RTC, | ||
431 | }, | ||
398 | }; | 432 | }; |
399 | 433 | ||
400 | static struct r8a66597_platdata r8a66597_data = { | 434 | static struct r8a66597_platdata r8a66597_data = { |
401 | /* This set zero to all members */ | 435 | .on_chip = 1, |
402 | }; | 436 | }; |
403 | 437 | ||
404 | static struct resource sh7723_usb_host_resources[] = { | 438 | static struct resource sh7723_usb_host_resources[] = { |
@@ -424,6 +458,9 @@ static struct platform_device sh7723_usb_host_device = { | |||
424 | }, | 458 | }, |
425 | .num_resources = ARRAY_SIZE(sh7723_usb_host_resources), | 459 | .num_resources = ARRAY_SIZE(sh7723_usb_host_resources), |
426 | .resource = sh7723_usb_host_resources, | 460 | .resource = sh7723_usb_host_resources, |
461 | .archdata = { | ||
462 | .hwblk_id = HWBLK_USB, | ||
463 | }, | ||
427 | }; | 464 | }; |
428 | 465 | ||
429 | static struct resource iic_resources[] = { | 466 | static struct resource iic_resources[] = { |
@@ -445,6 +482,9 @@ static struct platform_device iic_device = { | |||
445 | .id = 0, /* "i2c0" clock */ | 482 | .id = 0, /* "i2c0" clock */ |
446 | .num_resources = ARRAY_SIZE(iic_resources), | 483 | .num_resources = ARRAY_SIZE(iic_resources), |
447 | .resource = iic_resources, | 484 | .resource = iic_resources, |
485 | .archdata = { | ||
486 | .hwblk_id = HWBLK_IIC, | ||
487 | }, | ||
448 | }; | 488 | }; |
449 | 489 | ||
450 | static struct platform_device *sh7723_devices[] __initdata = { | 490 | static struct platform_device *sh7723_devices[] __initdata = { |
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c index a04edaab9a29..f3851fd757ec 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <asm/clock.h> | 23 | #include <asm/clock.h> |
24 | #include <asm/mmzone.h> | 24 | #include <asm/mmzone.h> |
25 | #include <cpu/sh7724.h> | ||
25 | 26 | ||
26 | /* Serial */ | 27 | /* Serial */ |
27 | static struct plat_sci_port sci_platform_data[] = { | 28 | static struct plat_sci_port sci_platform_data[] = { |
@@ -103,6 +104,9 @@ static struct platform_device rtc_device = { | |||
103 | .id = -1, | 104 | .id = -1, |
104 | .num_resources = ARRAY_SIZE(rtc_resources), | 105 | .num_resources = ARRAY_SIZE(rtc_resources), |
105 | .resource = rtc_resources, | 106 | .resource = rtc_resources, |
107 | .archdata = { | ||
108 | .hwblk_id = HWBLK_RTC, | ||
109 | }, | ||
106 | }; | 110 | }; |
107 | 111 | ||
108 | /* I2C0 */ | 112 | /* I2C0 */ |
@@ -125,6 +129,9 @@ static struct platform_device iic0_device = { | |||
125 | .id = 0, /* "i2c0" clock */ | 129 | .id = 0, /* "i2c0" clock */ |
126 | .num_resources = ARRAY_SIZE(iic0_resources), | 130 | .num_resources = ARRAY_SIZE(iic0_resources), |
127 | .resource = iic0_resources, | 131 | .resource = iic0_resources, |
132 | .archdata = { | ||
133 | .hwblk_id = HWBLK_IIC0, | ||
134 | }, | ||
128 | }; | 135 | }; |
129 | 136 | ||
130 | /* I2C1 */ | 137 | /* I2C1 */ |
@@ -147,6 +154,9 @@ static struct platform_device iic1_device = { | |||
147 | .id = 1, /* "i2c1" clock */ | 154 | .id = 1, /* "i2c1" clock */ |
148 | .num_resources = ARRAY_SIZE(iic1_resources), | 155 | .num_resources = ARRAY_SIZE(iic1_resources), |
149 | .resource = iic1_resources, | 156 | .resource = iic1_resources, |
157 | .archdata = { | ||
158 | .hwblk_id = HWBLK_IIC1, | ||
159 | }, | ||
150 | }; | 160 | }; |
151 | 161 | ||
152 | /* VPU */ | 162 | /* VPU */ |
@@ -176,6 +186,9 @@ static struct platform_device vpu_device = { | |||
176 | }, | 186 | }, |
177 | .resource = vpu_resources, | 187 | .resource = vpu_resources, |
178 | .num_resources = ARRAY_SIZE(vpu_resources), | 188 | .num_resources = ARRAY_SIZE(vpu_resources), |
189 | .archdata = { | ||
190 | .hwblk_id = HWBLK_VPU, | ||
191 | }, | ||
179 | }; | 192 | }; |
180 | 193 | ||
181 | /* VEU0 */ | 194 | /* VEU0 */ |
@@ -205,6 +218,9 @@ static struct platform_device veu0_device = { | |||
205 | }, | 218 | }, |
206 | .resource = veu0_resources, | 219 | .resource = veu0_resources, |
207 | .num_resources = ARRAY_SIZE(veu0_resources), | 220 | .num_resources = ARRAY_SIZE(veu0_resources), |
221 | .archdata = { | ||
222 | .hwblk_id = HWBLK_VEU0, | ||
223 | }, | ||
208 | }; | 224 | }; |
209 | 225 | ||
210 | /* VEU1 */ | 226 | /* VEU1 */ |
@@ -234,6 +250,9 @@ static struct platform_device veu1_device = { | |||
234 | }, | 250 | }, |
235 | .resource = veu1_resources, | 251 | .resource = veu1_resources, |
236 | .num_resources = ARRAY_SIZE(veu1_resources), | 252 | .num_resources = ARRAY_SIZE(veu1_resources), |
253 | .archdata = { | ||
254 | .hwblk_id = HWBLK_VEU1, | ||
255 | }, | ||
237 | }; | 256 | }; |
238 | 257 | ||
239 | static struct sh_timer_config cmt_platform_data = { | 258 | static struct sh_timer_config cmt_platform_data = { |
@@ -266,6 +285,9 @@ static struct platform_device cmt_device = { | |||
266 | }, | 285 | }, |
267 | .resource = cmt_resources, | 286 | .resource = cmt_resources, |
268 | .num_resources = ARRAY_SIZE(cmt_resources), | 287 | .num_resources = ARRAY_SIZE(cmt_resources), |
288 | .archdata = { | ||
289 | .hwblk_id = HWBLK_CMT, | ||
290 | }, | ||
269 | }; | 291 | }; |
270 | 292 | ||
271 | static struct sh_timer_config tmu0_platform_data = { | 293 | static struct sh_timer_config tmu0_platform_data = { |
@@ -297,6 +319,9 @@ static struct platform_device tmu0_device = { | |||
297 | }, | 319 | }, |
298 | .resource = tmu0_resources, | 320 | .resource = tmu0_resources, |
299 | .num_resources = ARRAY_SIZE(tmu0_resources), | 321 | .num_resources = ARRAY_SIZE(tmu0_resources), |
322 | .archdata = { | ||
323 | .hwblk_id = HWBLK_TMU0, | ||
324 | }, | ||
300 | }; | 325 | }; |
301 | 326 | ||
302 | static struct sh_timer_config tmu1_platform_data = { | 327 | static struct sh_timer_config tmu1_platform_data = { |
@@ -328,6 +353,9 @@ static struct platform_device tmu1_device = { | |||
328 | }, | 353 | }, |
329 | .resource = tmu1_resources, | 354 | .resource = tmu1_resources, |
330 | .num_resources = ARRAY_SIZE(tmu1_resources), | 355 | .num_resources = ARRAY_SIZE(tmu1_resources), |
356 | .archdata = { | ||
357 | .hwblk_id = HWBLK_TMU0, | ||
358 | }, | ||
331 | }; | 359 | }; |
332 | 360 | ||
333 | static struct sh_timer_config tmu2_platform_data = { | 361 | static struct sh_timer_config tmu2_platform_data = { |
@@ -358,6 +386,9 @@ static struct platform_device tmu2_device = { | |||
358 | }, | 386 | }, |
359 | .resource = tmu2_resources, | 387 | .resource = tmu2_resources, |
360 | .num_resources = ARRAY_SIZE(tmu2_resources), | 388 | .num_resources = ARRAY_SIZE(tmu2_resources), |
389 | .archdata = { | ||
390 | .hwblk_id = HWBLK_TMU0, | ||
391 | }, | ||
361 | }; | 392 | }; |
362 | 393 | ||
363 | 394 | ||
@@ -389,6 +420,9 @@ static struct platform_device tmu3_device = { | |||
389 | }, | 420 | }, |
390 | .resource = tmu3_resources, | 421 | .resource = tmu3_resources, |
391 | .num_resources = ARRAY_SIZE(tmu3_resources), | 422 | .num_resources = ARRAY_SIZE(tmu3_resources), |
423 | .archdata = { | ||
424 | .hwblk_id = HWBLK_TMU1, | ||
425 | }, | ||
392 | }; | 426 | }; |
393 | 427 | ||
394 | static struct sh_timer_config tmu4_platform_data = { | 428 | static struct sh_timer_config tmu4_platform_data = { |
@@ -419,6 +453,9 @@ static struct platform_device tmu4_device = { | |||
419 | }, | 453 | }, |
420 | .resource = tmu4_resources, | 454 | .resource = tmu4_resources, |
421 | .num_resources = ARRAY_SIZE(tmu4_resources), | 455 | .num_resources = ARRAY_SIZE(tmu4_resources), |
456 | .archdata = { | ||
457 | .hwblk_id = HWBLK_TMU1, | ||
458 | }, | ||
422 | }; | 459 | }; |
423 | 460 | ||
424 | static struct sh_timer_config tmu5_platform_data = { | 461 | static struct sh_timer_config tmu5_platform_data = { |
@@ -449,6 +486,9 @@ static struct platform_device tmu5_device = { | |||
449 | }, | 486 | }, |
450 | .resource = tmu5_resources, | 487 | .resource = tmu5_resources, |
451 | .num_resources = ARRAY_SIZE(tmu5_resources), | 488 | .num_resources = ARRAY_SIZE(tmu5_resources), |
489 | .archdata = { | ||
490 | .hwblk_id = HWBLK_TMU1, | ||
491 | }, | ||
452 | }; | 492 | }; |
453 | 493 | ||
454 | /* JPU */ | 494 | /* JPU */ |
@@ -478,6 +518,9 @@ static struct platform_device jpu_device = { | |||
478 | }, | 518 | }, |
479 | .resource = jpu_resources, | 519 | .resource = jpu_resources, |
480 | .num_resources = ARRAY_SIZE(jpu_resources), | 520 | .num_resources = ARRAY_SIZE(jpu_resources), |
521 | .archdata = { | ||
522 | .hwblk_id = HWBLK_JPU, | ||
523 | }, | ||
481 | }; | 524 | }; |
482 | 525 | ||
483 | static struct platform_device *sh7724_devices[] __initdata = { | 526 | static struct platform_device *sh7724_devices[] __initdata = { |
diff --git a/arch/sh/kernel/cpu/shmobile/Makefile b/arch/sh/kernel/cpu/shmobile/Makefile index 08bfa7c7db29..e8a5111e848a 100644 --- a/arch/sh/kernel/cpu/shmobile/Makefile +++ b/arch/sh/kernel/cpu/shmobile/Makefile | |||
@@ -4,3 +4,4 @@ | |||
4 | 4 | ||
5 | # Power Management & Sleep mode | 5 | # Power Management & Sleep mode |
6 | obj-$(CONFIG_PM) += pm.o sleep.o | 6 | obj-$(CONFIG_PM) += pm.o sleep.o |
7 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o | ||
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c new file mode 100644 index 000000000000..4afdd975cc66 --- /dev/null +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/shmobile/cpuidle.c | ||
3 | * | ||
4 | * Cpuidle support code for SuperH Mobile | ||
5 | * | ||
6 | * Copyright (C) 2009 Magnus Damm | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/io.h> | ||
15 | #include <linux/suspend.h> | ||
16 | #include <linux/cpuidle.h> | ||
17 | #include <asm/suspend.h> | ||
18 | #include <asm/uaccess.h> | ||
19 | #include <asm/hwblk.h> | ||
20 | |||
21 | static unsigned long cpuidle_mode[] = { | ||
22 | SUSP_SH_SLEEP, /* regular sleep mode */ | ||
23 | SUSP_SH_SLEEP | SUSP_SH_SF, /* sleep mode + self refresh */ | ||
24 | }; | ||
25 | |||
26 | static int cpuidle_sleep_enter(struct cpuidle_device *dev, | ||
27 | struct cpuidle_state *state) | ||
28 | { | ||
29 | unsigned long allowed_mode = arch_hwblk_sleep_mode(); | ||
30 | ktime_t before, after; | ||
31 | int requested_state = state - &dev->states[0]; | ||
32 | int allowed_state; | ||
33 | int k; | ||
34 | |||
35 | /* convert allowed mode to allowed state */ | ||
36 | for (k = ARRAY_SIZE(cpuidle_mode) - 1; k > 0; k--) | ||
37 | if (cpuidle_mode[k] == allowed_mode) | ||
38 | break; | ||
39 | |||
40 | allowed_state = k; | ||
41 | |||
42 | /* take the following into account for sleep mode selection: | ||
43 | * - allowed_state: best mode allowed by hardware (clock deps) | ||
44 | * - requested_state: best mode allowed by software (latencies) | ||
45 | */ | ||
46 | k = min_t(int, allowed_state, requested_state); | ||
47 | |||
48 | dev->last_state = &dev->states[k]; | ||
49 | before = ktime_get(); | ||
50 | sh_mobile_call_standby(cpuidle_mode[k]); | ||
51 | after = ktime_get(); | ||
52 | return ktime_to_ns(ktime_sub(after, before)) >> 10; | ||
53 | } | ||
54 | |||
55 | static struct cpuidle_device cpuidle_dev; | ||
56 | static struct cpuidle_driver cpuidle_driver = { | ||
57 | .name = "sh_idle", | ||
58 | .owner = THIS_MODULE, | ||
59 | }; | ||
60 | |||
61 | void sh_mobile_setup_cpuidle(void) | ||
62 | { | ||
63 | struct cpuidle_device *dev = &cpuidle_dev; | ||
64 | struct cpuidle_state *state; | ||
65 | int i; | ||
66 | |||
67 | cpuidle_register_driver(&cpuidle_driver); | ||
68 | |||
69 | for (i = 0; i < CPUIDLE_STATE_MAX; i++) { | ||
70 | dev->states[i].name[0] = '\0'; | ||
71 | dev->states[i].desc[0] = '\0'; | ||
72 | } | ||
73 | |||
74 | i = CPUIDLE_DRIVER_STATE_START; | ||
75 | |||
76 | state = &dev->states[i++]; | ||
77 | snprintf(state->name, CPUIDLE_NAME_LEN, "C0"); | ||
78 | strncpy(state->desc, "SuperH Sleep Mode", CPUIDLE_DESC_LEN); | ||
79 | state->exit_latency = 1; | ||
80 | state->target_residency = 1 * 2; | ||
81 | state->power_usage = 3; | ||
82 | state->flags = 0; | ||
83 | state->flags |= CPUIDLE_FLAG_SHALLOW; | ||
84 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
85 | state->enter = cpuidle_sleep_enter; | ||
86 | |||
87 | dev->safe_state = state; | ||
88 | |||
89 | state = &dev->states[i++]; | ||
90 | snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); | ||
91 | strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN); | ||
92 | state->exit_latency = 100; | ||
93 | state->target_residency = 1 * 2; | ||
94 | state->power_usage = 1; | ||
95 | state->flags = 0; | ||
96 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
97 | state->enter = cpuidle_sleep_enter; | ||
98 | |||
99 | dev->state_count = i; | ||
100 | |||
101 | cpuidle_register_device(dev); | ||
102 | } | ||
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c index 8c067adf6830..de078d24ce56 100644 --- a/arch/sh/kernel/cpu/shmobile/pm.c +++ b/arch/sh/kernel/cpu/shmobile/pm.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/sh/kernel/cpu/sh4a/pm-sh_mobile.c | 2 | * arch/sh/kernel/cpu/shmobile/pm.c |
3 | * | 3 | * |
4 | * Power management support code for SuperH Mobile | 4 | * Power management support code for SuperH Mobile |
5 | * | 5 | * |
@@ -32,20 +32,17 @@ | |||
32 | * | 32 | * |
33 | * R-standby mode is unsupported, but will be added in the future | 33 | * R-standby mode is unsupported, but will be added in the future |
34 | * U-standby mode is low priority since it needs bootloader hacks | 34 | * U-standby mode is low priority since it needs bootloader hacks |
35 | * | ||
36 | * All modes should be tied in with cpuidle. But before that can | ||
37 | * happen we need to keep track of enabled hardware blocks so we | ||
38 | * can avoid entering sleep modes that stop clocks to hardware | ||
39 | * blocks that are in use even though the cpu core is idle. | ||
40 | */ | 35 | */ |
41 | 36 | ||
37 | #define ILRAM_BASE 0xe5200000 | ||
38 | |||
42 | extern const unsigned char sh_mobile_standby[]; | 39 | extern const unsigned char sh_mobile_standby[]; |
43 | extern const unsigned int sh_mobile_standby_size; | 40 | extern const unsigned int sh_mobile_standby_size; |
44 | 41 | ||
45 | static void sh_mobile_call_standby(unsigned long mode) | 42 | void sh_mobile_call_standby(unsigned long mode) |
46 | { | 43 | { |
47 | extern void *vbr_base; | 44 | extern void *vbr_base; |
48 | void *onchip_mem = (void *)0xe5200000; /* ILRAM */ | 45 | void *onchip_mem = (void *)ILRAM_BASE; |
49 | void (*standby_onchip_mem)(unsigned long) = onchip_mem; | 46 | void (*standby_onchip_mem)(unsigned long) = onchip_mem; |
50 | 47 | ||
51 | /* Note: Wake up from sleep may generate exceptions! | 48 | /* Note: Wake up from sleep may generate exceptions! |
@@ -55,11 +52,6 @@ static void sh_mobile_call_standby(unsigned long mode) | |||
55 | if (mode & SUSP_SH_SF) | 52 | if (mode & SUSP_SH_SF) |
56 | asm volatile("ldc %0, vbr" : : "r" (onchip_mem) : "memory"); | 53 | asm volatile("ldc %0, vbr" : : "r" (onchip_mem) : "memory"); |
57 | 54 | ||
58 | /* Copy the assembly snippet to the otherwise ununsed ILRAM */ | ||
59 | memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size); | ||
60 | wmb(); | ||
61 | ctrl_barrier(); | ||
62 | |||
63 | /* Let assembly snippet in on-chip memory handle the rest */ | 55 | /* Let assembly snippet in on-chip memory handle the rest */ |
64 | standby_onchip_mem(mode); | 56 | standby_onchip_mem(mode); |
65 | 57 | ||
@@ -85,7 +77,15 @@ static struct platform_suspend_ops sh_pm_ops = { | |||
85 | 77 | ||
86 | static int __init sh_pm_init(void) | 78 | static int __init sh_pm_init(void) |
87 | { | 79 | { |
80 | void *onchip_mem = (void *)ILRAM_BASE; | ||
81 | |||
82 | /* Copy the assembly snippet to the otherwise ununsed ILRAM */ | ||
83 | memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size); | ||
84 | wmb(); | ||
85 | ctrl_barrier(); | ||
86 | |||
88 | suspend_set_ops(&sh_pm_ops); | 87 | suspend_set_ops(&sh_pm_ops); |
88 | sh_mobile_setup_cpuidle(); | ||
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | 91 | ||
diff --git a/arch/sh/kernel/dumpstack.c b/arch/sh/kernel/dumpstack.c new file mode 100644 index 000000000000..6f5ad1513409 --- /dev/null +++ b/arch/sh/kernel/dumpstack.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
3 | * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs | ||
4 | * Copyright (C) 2009 Matt Fleming | ||
5 | */ | ||
6 | #include <linux/kallsyms.h> | ||
7 | #include <linux/ftrace.h> | ||
8 | #include <linux/debug_locks.h> | ||
9 | #include <asm/unwinder.h> | ||
10 | #include <asm/stacktrace.h> | ||
11 | |||
12 | void printk_address(unsigned long address, int reliable) | ||
13 | { | ||
14 | printk(" [<%p>] %s%pS\n", (void *) address, | ||
15 | reliable ? "" : "? ", (void *) address); | ||
16 | } | ||
17 | |||
18 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
19 | static void | ||
20 | print_ftrace_graph_addr(unsigned long addr, void *data, | ||
21 | const struct stacktrace_ops *ops, | ||
22 | struct thread_info *tinfo, int *graph) | ||
23 | { | ||
24 | struct task_struct *task = tinfo->task; | ||
25 | unsigned long ret_addr; | ||
26 | int index = task->curr_ret_stack; | ||
27 | |||
28 | if (addr != (unsigned long)return_to_handler) | ||
29 | return; | ||
30 | |||
31 | if (!task->ret_stack || index < *graph) | ||
32 | return; | ||
33 | |||
34 | index -= *graph; | ||
35 | ret_addr = task->ret_stack[index].ret; | ||
36 | |||
37 | ops->address(data, ret_addr, 1); | ||
38 | |||
39 | (*graph)++; | ||
40 | } | ||
41 | #else | ||
42 | static inline void | ||
43 | print_ftrace_graph_addr(unsigned long addr, void *data, | ||
44 | const struct stacktrace_ops *ops, | ||
45 | struct thread_info *tinfo, int *graph) | ||
46 | { } | ||
47 | #endif | ||
48 | |||
49 | void | ||
50 | stack_reader_dump(struct task_struct *task, struct pt_regs *regs, | ||
51 | unsigned long *sp, const struct stacktrace_ops *ops, | ||
52 | void *data) | ||
53 | { | ||
54 | struct thread_info *context; | ||
55 | int graph = 0; | ||
56 | |||
57 | context = (struct thread_info *) | ||
58 | ((unsigned long)sp & (~(THREAD_SIZE - 1))); | ||
59 | |||
60 | while (!kstack_end(sp)) { | ||
61 | unsigned long addr = *sp++; | ||
62 | |||
63 | if (__kernel_text_address(addr)) { | ||
64 | ops->address(data, addr, 1); | ||
65 | |||
66 | print_ftrace_graph_addr(addr, data, ops, | ||
67 | context, &graph); | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | static void | ||
73 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
74 | { | ||
75 | printk(data); | ||
76 | print_symbol(msg, symbol); | ||
77 | printk("\n"); | ||
78 | } | ||
79 | |||
80 | static void print_trace_warning(void *data, char *msg) | ||
81 | { | ||
82 | printk("%s%s\n", (char *)data, msg); | ||
83 | } | ||
84 | |||
85 | static int print_trace_stack(void *data, char *name) | ||
86 | { | ||
87 | printk("%s <%s> ", (char *)data, name); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Print one address/symbol entries per line. | ||
93 | */ | ||
94 | static void print_trace_address(void *data, unsigned long addr, int reliable) | ||
95 | { | ||
96 | printk(data); | ||
97 | printk_address(addr, reliable); | ||
98 | } | ||
99 | |||
100 | static const struct stacktrace_ops print_trace_ops = { | ||
101 | .warning = print_trace_warning, | ||
102 | .warning_symbol = print_trace_warning_symbol, | ||
103 | .stack = print_trace_stack, | ||
104 | .address = print_trace_address, | ||
105 | }; | ||
106 | |||
107 | void show_trace(struct task_struct *tsk, unsigned long *sp, | ||
108 | struct pt_regs *regs) | ||
109 | { | ||
110 | if (regs && user_mode(regs)) | ||
111 | return; | ||
112 | |||
113 | printk("\nCall trace:\n"); | ||
114 | |||
115 | unwind_stack(tsk, regs, sp, &print_trace_ops, ""); | ||
116 | |||
117 | printk("\n"); | ||
118 | |||
119 | if (!tsk) | ||
120 | tsk = current; | ||
121 | |||
122 | debug_show_held_locks(tsk); | ||
123 | } | ||
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c new file mode 100644 index 000000000000..c6c5764a8ab1 --- /dev/null +++ b/arch/sh/kernel/dwarf.c | |||
@@ -0,0 +1,902 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Matt Fleming <matt@console-pimps.org> | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * This is an implementation of a DWARF unwinder. Its main purpose is | ||
9 | * for generating stacktrace information. Based on the DWARF 3 | ||
10 | * specification from http://www.dwarfstd.org. | ||
11 | * | ||
12 | * TODO: | ||
13 | * - DWARF64 doesn't work. | ||
14 | */ | ||
15 | |||
16 | /* #define DEBUG */ | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <asm/dwarf.h> | ||
22 | #include <asm/unwinder.h> | ||
23 | #include <asm/sections.h> | ||
24 | #include <asm/unaligned.h> | ||
25 | #include <asm/dwarf.h> | ||
26 | #include <asm/stacktrace.h> | ||
27 | |||
28 | static LIST_HEAD(dwarf_cie_list); | ||
29 | DEFINE_SPINLOCK(dwarf_cie_lock); | ||
30 | |||
31 | static LIST_HEAD(dwarf_fde_list); | ||
32 | DEFINE_SPINLOCK(dwarf_fde_lock); | ||
33 | |||
34 | static struct dwarf_cie *cached_cie; | ||
35 | |||
36 | /* | ||
37 | * Figure out whether we need to allocate some dwarf registers. If dwarf | ||
38 | * registers have already been allocated then we may need to realloc | ||
39 | * them. "reg" is a register number that we need to be able to access | ||
40 | * after this call. | ||
41 | * | ||
42 | * Register numbers start at zero, therefore we need to allocate space | ||
43 | * for "reg" + 1 registers. | ||
44 | */ | ||
45 | static void dwarf_frame_alloc_regs(struct dwarf_frame *frame, | ||
46 | unsigned int reg) | ||
47 | { | ||
48 | struct dwarf_reg *regs; | ||
49 | unsigned int num_regs = reg + 1; | ||
50 | size_t new_size; | ||
51 | size_t old_size; | ||
52 | |||
53 | new_size = num_regs * sizeof(*regs); | ||
54 | old_size = frame->num_regs * sizeof(*regs); | ||
55 | |||
56 | /* Fast path: don't allocate any regs if we've already got enough. */ | ||
57 | if (frame->num_regs >= num_regs) | ||
58 | return; | ||
59 | |||
60 | regs = kzalloc(new_size, GFP_ATOMIC); | ||
61 | if (!regs) { | ||
62 | printk(KERN_WARNING "Unable to allocate DWARF registers\n"); | ||
63 | /* | ||
64 | * Let's just bomb hard here, we have no way to | ||
65 | * gracefully recover. | ||
66 | */ | ||
67 | BUG(); | ||
68 | } | ||
69 | |||
70 | if (frame->regs) { | ||
71 | memcpy(regs, frame->regs, old_size); | ||
72 | kfree(frame->regs); | ||
73 | } | ||
74 | |||
75 | frame->regs = regs; | ||
76 | frame->num_regs = num_regs; | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * dwarf_read_addr - read dwarf data | ||
81 | * @src: source address of data | ||
82 | * @dst: destination address to store the data to | ||
83 | * | ||
84 | * Read 'n' bytes from @src, where 'n' is the size of an address on | ||
85 | * the native machine. We return the number of bytes read, which | ||
86 | * should always be 'n'. We also have to be careful when reading | ||
87 | * from @src and writing to @dst, because they can be arbitrarily | ||
88 | * aligned. Return 'n' - the number of bytes read. | ||
89 | */ | ||
90 | static inline int dwarf_read_addr(unsigned long *src, unsigned long *dst) | ||
91 | { | ||
92 | u32 val = get_unaligned(src); | ||
93 | put_unaligned(val, dst); | ||
94 | return sizeof(unsigned long *); | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * dwarf_read_uleb128 - read unsigned LEB128 data | ||
99 | * @addr: the address where the ULEB128 data is stored | ||
100 | * @ret: address to store the result | ||
101 | * | ||
102 | * Decode an unsigned LEB128 encoded datum. The algorithm is taken | ||
103 | * from Appendix C of the DWARF 3 spec. For information on the | ||
104 | * encodings refer to section "7.6 - Variable Length Data". Return | ||
105 | * the number of bytes read. | ||
106 | */ | ||
107 | static inline unsigned long dwarf_read_uleb128(char *addr, unsigned int *ret) | ||
108 | { | ||
109 | unsigned int result; | ||
110 | unsigned char byte; | ||
111 | int shift, count; | ||
112 | |||
113 | result = 0; | ||
114 | shift = 0; | ||
115 | count = 0; | ||
116 | |||
117 | while (1) { | ||
118 | byte = __raw_readb(addr); | ||
119 | addr++; | ||
120 | count++; | ||
121 | |||
122 | result |= (byte & 0x7f) << shift; | ||
123 | shift += 7; | ||
124 | |||
125 | if (!(byte & 0x80)) | ||
126 | break; | ||
127 | } | ||
128 | |||
129 | *ret = result; | ||
130 | |||
131 | return count; | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * dwarf_read_leb128 - read signed LEB128 data | ||
136 | * @addr: the address of the LEB128 encoded data | ||
137 | * @ret: address to store the result | ||
138 | * | ||
139 | * Decode signed LEB128 data. The algorithm is taken from Appendix | ||
140 | * C of the DWARF 3 spec. Return the number of bytes read. | ||
141 | */ | ||
142 | static inline unsigned long dwarf_read_leb128(char *addr, int *ret) | ||
143 | { | ||
144 | unsigned char byte; | ||
145 | int result, shift; | ||
146 | int num_bits; | ||
147 | int count; | ||
148 | |||
149 | result = 0; | ||
150 | shift = 0; | ||
151 | count = 0; | ||
152 | |||
153 | while (1) { | ||
154 | byte = __raw_readb(addr); | ||
155 | addr++; | ||
156 | result |= (byte & 0x7f) << shift; | ||
157 | shift += 7; | ||
158 | count++; | ||
159 | |||
160 | if (!(byte & 0x80)) | ||
161 | break; | ||
162 | } | ||
163 | |||
164 | /* The number of bits in a signed integer. */ | ||
165 | num_bits = 8 * sizeof(result); | ||
166 | |||
167 | if ((shift < num_bits) && (byte & 0x40)) | ||
168 | result |= (-1 << shift); | ||
169 | |||
170 | *ret = result; | ||
171 | |||
172 | return count; | ||
173 | } | ||
174 | |||
175 | /** | ||
176 | * dwarf_read_encoded_value - return the decoded value at @addr | ||
177 | * @addr: the address of the encoded value | ||
178 | * @val: where to write the decoded value | ||
179 | * @encoding: the encoding with which we can decode @addr | ||
180 | * | ||
181 | * GCC emits encoded address in the .eh_frame FDE entries. Decode | ||
182 | * the value at @addr using @encoding. The decoded value is written | ||
183 | * to @val and the number of bytes read is returned. | ||
184 | */ | ||
185 | static int dwarf_read_encoded_value(char *addr, unsigned long *val, | ||
186 | char encoding) | ||
187 | { | ||
188 | unsigned long decoded_addr = 0; | ||
189 | int count = 0; | ||
190 | |||
191 | switch (encoding & 0x70) { | ||
192 | case DW_EH_PE_absptr: | ||
193 | break; | ||
194 | case DW_EH_PE_pcrel: | ||
195 | decoded_addr = (unsigned long)addr; | ||
196 | break; | ||
197 | default: | ||
198 | pr_debug("encoding=0x%x\n", (encoding & 0x70)); | ||
199 | BUG(); | ||
200 | } | ||
201 | |||
202 | if ((encoding & 0x07) == 0x00) | ||
203 | encoding |= DW_EH_PE_udata4; | ||
204 | |||
205 | switch (encoding & 0x0f) { | ||
206 | case DW_EH_PE_sdata4: | ||
207 | case DW_EH_PE_udata4: | ||
208 | count += 4; | ||
209 | decoded_addr += get_unaligned((u32 *)addr); | ||
210 | __raw_writel(decoded_addr, val); | ||
211 | break; | ||
212 | default: | ||
213 | pr_debug("encoding=0x%x\n", encoding); | ||
214 | BUG(); | ||
215 | } | ||
216 | |||
217 | return count; | ||
218 | } | ||
219 | |||
220 | /** | ||
221 | * dwarf_entry_len - return the length of an FDE or CIE | ||
222 | * @addr: the address of the entry | ||
223 | * @len: the length of the entry | ||
224 | * | ||
225 | * Read the initial_length field of the entry and store the size of | ||
226 | * the entry in @len. We return the number of bytes read. Return a | ||
227 | * count of 0 on error. | ||
228 | */ | ||
229 | static inline int dwarf_entry_len(char *addr, unsigned long *len) | ||
230 | { | ||
231 | u32 initial_len; | ||
232 | int count; | ||
233 | |||
234 | initial_len = get_unaligned((u32 *)addr); | ||
235 | count = 4; | ||
236 | |||
237 | /* | ||
238 | * An initial length field value in the range DW_LEN_EXT_LO - | ||
239 | * DW_LEN_EXT_HI indicates an extension, and should not be | ||
240 | * interpreted as a length. The only extension that we currently | ||
241 | * understand is the use of DWARF64 addresses. | ||
242 | */ | ||
243 | if (initial_len >= DW_EXT_LO && initial_len <= DW_EXT_HI) { | ||
244 | /* | ||
245 | * The 64-bit length field immediately follows the | ||
246 | * compulsory 32-bit length field. | ||
247 | */ | ||
248 | if (initial_len == DW_EXT_DWARF64) { | ||
249 | *len = get_unaligned((u64 *)addr + 4); | ||
250 | count = 12; | ||
251 | } else { | ||
252 | printk(KERN_WARNING "Unknown DWARF extension\n"); | ||
253 | count = 0; | ||
254 | } | ||
255 | } else | ||
256 | *len = initial_len; | ||
257 | |||
258 | return count; | ||
259 | } | ||
260 | |||
261 | /** | ||
262 | * dwarf_lookup_cie - locate the cie | ||
263 | * @cie_ptr: pointer to help with lookup | ||
264 | */ | ||
265 | static struct dwarf_cie *dwarf_lookup_cie(unsigned long cie_ptr) | ||
266 | { | ||
267 | struct dwarf_cie *cie, *n; | ||
268 | unsigned long flags; | ||
269 | |||
270 | spin_lock_irqsave(&dwarf_cie_lock, flags); | ||
271 | |||
272 | /* | ||
273 | * We've cached the last CIE we looked up because chances are | ||
274 | * that the FDE wants this CIE. | ||
275 | */ | ||
276 | if (cached_cie && cached_cie->cie_pointer == cie_ptr) { | ||
277 | cie = cached_cie; | ||
278 | goto out; | ||
279 | } | ||
280 | |||
281 | list_for_each_entry_safe(cie, n, &dwarf_cie_list, link) { | ||
282 | if (cie->cie_pointer == cie_ptr) { | ||
283 | cached_cie = cie; | ||
284 | break; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | /* Couldn't find the entry in the list. */ | ||
289 | if (&cie->link == &dwarf_cie_list) | ||
290 | cie = NULL; | ||
291 | out: | ||
292 | spin_unlock_irqrestore(&dwarf_cie_lock, flags); | ||
293 | return cie; | ||
294 | } | ||
295 | |||
296 | /** | ||
297 | * dwarf_lookup_fde - locate the FDE that covers pc | ||
298 | * @pc: the program counter | ||
299 | */ | ||
300 | struct dwarf_fde *dwarf_lookup_fde(unsigned long pc) | ||
301 | { | ||
302 | unsigned long flags; | ||
303 | struct dwarf_fde *fde, *n; | ||
304 | |||
305 | spin_lock_irqsave(&dwarf_fde_lock, flags); | ||
306 | list_for_each_entry_safe(fde, n, &dwarf_fde_list, link) { | ||
307 | unsigned long start, end; | ||
308 | |||
309 | start = fde->initial_location; | ||
310 | end = fde->initial_location + fde->address_range; | ||
311 | |||
312 | if (pc >= start && pc < end) | ||
313 | break; | ||
314 | } | ||
315 | |||
316 | /* Couldn't find the entry in the list. */ | ||
317 | if (&fde->link == &dwarf_fde_list) | ||
318 | fde = NULL; | ||
319 | |||
320 | spin_unlock_irqrestore(&dwarf_fde_lock, flags); | ||
321 | |||
322 | return fde; | ||
323 | } | ||
324 | |||
325 | /** | ||
326 | * dwarf_cfa_execute_insns - execute instructions to calculate a CFA | ||
327 | * @insn_start: address of the first instruction | ||
328 | * @insn_end: address of the last instruction | ||
329 | * @cie: the CIE for this function | ||
330 | * @fde: the FDE for this function | ||
331 | * @frame: the instructions calculate the CFA for this frame | ||
332 | * @pc: the program counter of the address we're interested in | ||
333 | * @define_ra: keep executing insns until the return addr reg is defined? | ||
334 | * | ||
335 | * Execute the Call Frame instruction sequence starting at | ||
336 | * @insn_start and ending at @insn_end. The instructions describe | ||
337 | * how to calculate the Canonical Frame Address of a stackframe. | ||
338 | * Store the results in @frame. | ||
339 | */ | ||
340 | static int dwarf_cfa_execute_insns(unsigned char *insn_start, | ||
341 | unsigned char *insn_end, | ||
342 | struct dwarf_cie *cie, | ||
343 | struct dwarf_fde *fde, | ||
344 | struct dwarf_frame *frame, | ||
345 | unsigned long pc, | ||
346 | bool define_ra) | ||
347 | { | ||
348 | unsigned char insn; | ||
349 | unsigned char *current_insn; | ||
350 | unsigned int count, delta, reg, expr_len, offset; | ||
351 | bool seen_ra_reg; | ||
352 | |||
353 | current_insn = insn_start; | ||
354 | |||
355 | /* | ||
356 | * If we're executing instructions for the dwarf_unwind_stack() | ||
357 | * FDE we need to keep executing instructions until the value of | ||
358 | * DWARF_ARCH_RA_REG is defined. See the comment in | ||
359 | * dwarf_unwind_stack() for more details. | ||
360 | */ | ||
361 | if (define_ra) | ||
362 | seen_ra_reg = false; | ||
363 | else | ||
364 | seen_ra_reg = true; | ||
365 | |||
366 | while (current_insn < insn_end && (frame->pc <= pc || !seen_ra_reg) ) { | ||
367 | insn = __raw_readb(current_insn++); | ||
368 | |||
369 | if (!seen_ra_reg) { | ||
370 | if (frame->num_regs >= DWARF_ARCH_RA_REG && | ||
371 | frame->regs[DWARF_ARCH_RA_REG].flags) | ||
372 | seen_ra_reg = true; | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Firstly, handle the opcodes that embed their operands | ||
377 | * in the instructions. | ||
378 | */ | ||
379 | switch (DW_CFA_opcode(insn)) { | ||
380 | case DW_CFA_advance_loc: | ||
381 | delta = DW_CFA_operand(insn); | ||
382 | delta *= cie->code_alignment_factor; | ||
383 | frame->pc += delta; | ||
384 | continue; | ||
385 | /* NOTREACHED */ | ||
386 | case DW_CFA_offset: | ||
387 | reg = DW_CFA_operand(insn); | ||
388 | count = dwarf_read_uleb128(current_insn, &offset); | ||
389 | current_insn += count; | ||
390 | offset *= cie->data_alignment_factor; | ||
391 | dwarf_frame_alloc_regs(frame, reg); | ||
392 | frame->regs[reg].addr = offset; | ||
393 | frame->regs[reg].flags |= DWARF_REG_OFFSET; | ||
394 | continue; | ||
395 | /* NOTREACHED */ | ||
396 | case DW_CFA_restore: | ||
397 | reg = DW_CFA_operand(insn); | ||
398 | continue; | ||
399 | /* NOTREACHED */ | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Secondly, handle the opcodes that don't embed their | ||
404 | * operands in the instruction. | ||
405 | */ | ||
406 | switch (insn) { | ||
407 | case DW_CFA_nop: | ||
408 | continue; | ||
409 | case DW_CFA_advance_loc1: | ||
410 | delta = *current_insn++; | ||
411 | frame->pc += delta * cie->code_alignment_factor; | ||
412 | break; | ||
413 | case DW_CFA_advance_loc2: | ||
414 | delta = get_unaligned((u16 *)current_insn); | ||
415 | current_insn += 2; | ||
416 | frame->pc += delta * cie->code_alignment_factor; | ||
417 | break; | ||
418 | case DW_CFA_advance_loc4: | ||
419 | delta = get_unaligned((u32 *)current_insn); | ||
420 | current_insn += 4; | ||
421 | frame->pc += delta * cie->code_alignment_factor; | ||
422 | break; | ||
423 | case DW_CFA_offset_extended: | ||
424 | count = dwarf_read_uleb128(current_insn, ®); | ||
425 | current_insn += count; | ||
426 | count = dwarf_read_uleb128(current_insn, &offset); | ||
427 | current_insn += count; | ||
428 | offset *= cie->data_alignment_factor; | ||
429 | break; | ||
430 | case DW_CFA_restore_extended: | ||
431 | count = dwarf_read_uleb128(current_insn, ®); | ||
432 | current_insn += count; | ||
433 | break; | ||
434 | case DW_CFA_undefined: | ||
435 | count = dwarf_read_uleb128(current_insn, ®); | ||
436 | current_insn += count; | ||
437 | break; | ||
438 | case DW_CFA_def_cfa: | ||
439 | count = dwarf_read_uleb128(current_insn, | ||
440 | &frame->cfa_register); | ||
441 | current_insn += count; | ||
442 | count = dwarf_read_uleb128(current_insn, | ||
443 | &frame->cfa_offset); | ||
444 | current_insn += count; | ||
445 | |||
446 | frame->flags |= DWARF_FRAME_CFA_REG_OFFSET; | ||
447 | break; | ||
448 | case DW_CFA_def_cfa_register: | ||
449 | count = dwarf_read_uleb128(current_insn, | ||
450 | &frame->cfa_register); | ||
451 | current_insn += count; | ||
452 | frame->cfa_offset = 0; | ||
453 | frame->flags |= DWARF_FRAME_CFA_REG_OFFSET; | ||
454 | break; | ||
455 | case DW_CFA_def_cfa_offset: | ||
456 | count = dwarf_read_uleb128(current_insn, &offset); | ||
457 | current_insn += count; | ||
458 | frame->cfa_offset = offset; | ||
459 | break; | ||
460 | case DW_CFA_def_cfa_expression: | ||
461 | count = dwarf_read_uleb128(current_insn, &expr_len); | ||
462 | current_insn += count; | ||
463 | |||
464 | frame->cfa_expr = current_insn; | ||
465 | frame->cfa_expr_len = expr_len; | ||
466 | current_insn += expr_len; | ||
467 | |||
468 | frame->flags |= DWARF_FRAME_CFA_REG_EXP; | ||
469 | break; | ||
470 | case DW_CFA_offset_extended_sf: | ||
471 | count = dwarf_read_uleb128(current_insn, ®); | ||
472 | current_insn += count; | ||
473 | count = dwarf_read_leb128(current_insn, &offset); | ||
474 | current_insn += count; | ||
475 | offset *= cie->data_alignment_factor; | ||
476 | dwarf_frame_alloc_regs(frame, reg); | ||
477 | frame->regs[reg].flags |= DWARF_REG_OFFSET; | ||
478 | frame->regs[reg].addr = offset; | ||
479 | break; | ||
480 | case DW_CFA_val_offset: | ||
481 | count = dwarf_read_uleb128(current_insn, ®); | ||
482 | current_insn += count; | ||
483 | count = dwarf_read_leb128(current_insn, &offset); | ||
484 | offset *= cie->data_alignment_factor; | ||
485 | frame->regs[reg].flags |= DWARF_REG_OFFSET; | ||
486 | frame->regs[reg].addr = offset; | ||
487 | break; | ||
488 | default: | ||
489 | pr_debug("unhandled DWARF instruction 0x%x\n", insn); | ||
490 | break; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | /** | ||
498 | * dwarf_unwind_stack - recursively unwind the stack | ||
499 | * @pc: address of the function to unwind | ||
500 | * @prev: struct dwarf_frame of the previous stackframe on the callstack | ||
501 | * | ||
502 | * Return a struct dwarf_frame representing the most recent frame | ||
503 | * on the callstack. Each of the lower (older) stack frames are | ||
504 | * linked via the "prev" member. | ||
505 | */ | ||
506 | struct dwarf_frame *dwarf_unwind_stack(unsigned long pc, | ||
507 | struct dwarf_frame *prev) | ||
508 | { | ||
509 | struct dwarf_frame *frame; | ||
510 | struct dwarf_cie *cie; | ||
511 | struct dwarf_fde *fde; | ||
512 | unsigned long addr; | ||
513 | int i, offset; | ||
514 | bool define_ra = false; | ||
515 | |||
516 | /* | ||
517 | * If this is the first invocation of this recursive function we | ||
518 | * need get the contents of a physical register to get the CFA | ||
519 | * in order to begin the virtual unwinding of the stack. | ||
520 | * | ||
521 | * Setting "define_ra" to true indictates that we want | ||
522 | * dwarf_cfa_execute_insns() to continue executing instructions | ||
523 | * until we know how to calculate the value of DWARF_ARCH_RA_REG | ||
524 | * (which we need in order to kick off the whole unwinding | ||
525 | * process). | ||
526 | * | ||
527 | * NOTE: the return address is guaranteed to be setup by the | ||
528 | * time this function makes its first function call. | ||
529 | */ | ||
530 | if (!pc && !prev) { | ||
531 | pc = (unsigned long)&dwarf_unwind_stack; | ||
532 | define_ra = true; | ||
533 | } | ||
534 | |||
535 | frame = kzalloc(sizeof(*frame), GFP_ATOMIC); | ||
536 | if (!frame) | ||
537 | return NULL; | ||
538 | |||
539 | frame->prev = prev; | ||
540 | |||
541 | fde = dwarf_lookup_fde(pc); | ||
542 | if (!fde) { | ||
543 | /* | ||
544 | * This is our normal exit path - the one that stops the | ||
545 | * recursion. There's two reasons why we might exit | ||
546 | * here, | ||
547 | * | ||
548 | * a) pc has no asscociated DWARF frame info and so | ||
549 | * we don't know how to unwind this frame. This is | ||
550 | * usually the case when we're trying to unwind a | ||
551 | * frame that was called from some assembly code | ||
552 | * that has no DWARF info, e.g. syscalls. | ||
553 | * | ||
554 | * b) the DEBUG info for pc is bogus. There's | ||
555 | * really no way to distinguish this case from the | ||
556 | * case above, which sucks because we could print a | ||
557 | * warning here. | ||
558 | */ | ||
559 | return NULL; | ||
560 | } | ||
561 | |||
562 | cie = dwarf_lookup_cie(fde->cie_pointer); | ||
563 | |||
564 | frame->pc = fde->initial_location; | ||
565 | |||
566 | /* CIE initial instructions */ | ||
567 | dwarf_cfa_execute_insns(cie->initial_instructions, | ||
568 | cie->instructions_end, cie, fde, | ||
569 | frame, pc, false); | ||
570 | |||
571 | /* FDE instructions */ | ||
572 | dwarf_cfa_execute_insns(fde->instructions, fde->end, cie, | ||
573 | fde, frame, pc, define_ra); | ||
574 | |||
575 | /* Calculate the CFA */ | ||
576 | switch (frame->flags) { | ||
577 | case DWARF_FRAME_CFA_REG_OFFSET: | ||
578 | if (prev) { | ||
579 | BUG_ON(!prev->regs[frame->cfa_register].flags); | ||
580 | |||
581 | addr = prev->cfa; | ||
582 | addr += prev->regs[frame->cfa_register].addr; | ||
583 | frame->cfa = __raw_readl(addr); | ||
584 | |||
585 | } else { | ||
586 | /* | ||
587 | * Again, this is the first invocation of this | ||
588 | * recurisve function. We need to physically | ||
589 | * read the contents of a register in order to | ||
590 | * get the Canonical Frame Address for this | ||
591 | * function. | ||
592 | */ | ||
593 | frame->cfa = dwarf_read_arch_reg(frame->cfa_register); | ||
594 | } | ||
595 | |||
596 | frame->cfa += frame->cfa_offset; | ||
597 | break; | ||
598 | default: | ||
599 | BUG(); | ||
600 | } | ||
601 | |||
602 | /* If we haven't seen the return address reg, we're screwed. */ | ||
603 | BUG_ON(!frame->regs[DWARF_ARCH_RA_REG].flags); | ||
604 | |||
605 | for (i = 0; i <= frame->num_regs; i++) { | ||
606 | struct dwarf_reg *reg = &frame->regs[i]; | ||
607 | |||
608 | if (!reg->flags) | ||
609 | continue; | ||
610 | |||
611 | offset = reg->addr; | ||
612 | offset += frame->cfa; | ||
613 | } | ||
614 | |||
615 | addr = frame->cfa + frame->regs[DWARF_ARCH_RA_REG].addr; | ||
616 | frame->return_addr = __raw_readl(addr); | ||
617 | |||
618 | frame->next = dwarf_unwind_stack(frame->return_addr, frame); | ||
619 | return frame; | ||
620 | } | ||
621 | |||
622 | static int dwarf_parse_cie(void *entry, void *p, unsigned long len, | ||
623 | unsigned char *end) | ||
624 | { | ||
625 | struct dwarf_cie *cie; | ||
626 | unsigned long flags; | ||
627 | int count; | ||
628 | |||
629 | cie = kzalloc(sizeof(*cie), GFP_KERNEL); | ||
630 | if (!cie) | ||
631 | return -ENOMEM; | ||
632 | |||
633 | cie->length = len; | ||
634 | |||
635 | /* | ||
636 | * Record the offset into the .eh_frame section | ||
637 | * for this CIE. It allows this CIE to be | ||
638 | * quickly and easily looked up from the | ||
639 | * corresponding FDE. | ||
640 | */ | ||
641 | cie->cie_pointer = (unsigned long)entry; | ||
642 | |||
643 | cie->version = *(char *)p++; | ||
644 | BUG_ON(cie->version != 1); | ||
645 | |||
646 | cie->augmentation = p; | ||
647 | p += strlen(cie->augmentation) + 1; | ||
648 | |||
649 | count = dwarf_read_uleb128(p, &cie->code_alignment_factor); | ||
650 | p += count; | ||
651 | |||
652 | count = dwarf_read_leb128(p, &cie->data_alignment_factor); | ||
653 | p += count; | ||
654 | |||
655 | /* | ||
656 | * Which column in the rule table contains the | ||
657 | * return address? | ||
658 | */ | ||
659 | if (cie->version == 1) { | ||
660 | cie->return_address_reg = __raw_readb(p); | ||
661 | p++; | ||
662 | } else { | ||
663 | count = dwarf_read_uleb128(p, &cie->return_address_reg); | ||
664 | p += count; | ||
665 | } | ||
666 | |||
667 | if (cie->augmentation[0] == 'z') { | ||
668 | unsigned int length, count; | ||
669 | cie->flags |= DWARF_CIE_Z_AUGMENTATION; | ||
670 | |||
671 | count = dwarf_read_uleb128(p, &length); | ||
672 | p += count; | ||
673 | |||
674 | BUG_ON((unsigned char *)p > end); | ||
675 | |||
676 | cie->initial_instructions = p + length; | ||
677 | cie->augmentation++; | ||
678 | } | ||
679 | |||
680 | while (*cie->augmentation) { | ||
681 | /* | ||
682 | * "L" indicates a byte showing how the | ||
683 | * LSDA pointer is encoded. Skip it. | ||
684 | */ | ||
685 | if (*cie->augmentation == 'L') { | ||
686 | p++; | ||
687 | cie->augmentation++; | ||
688 | } else if (*cie->augmentation == 'R') { | ||
689 | /* | ||
690 | * "R" indicates a byte showing | ||
691 | * how FDE addresses are | ||
692 | * encoded. | ||
693 | */ | ||
694 | cie->encoding = *(char *)p++; | ||
695 | cie->augmentation++; | ||
696 | } else if (*cie->augmentation == 'P') { | ||
697 | /* | ||
698 | * "R" indicates a personality | ||
699 | * routine in the CIE | ||
700 | * augmentation. | ||
701 | */ | ||
702 | BUG(); | ||
703 | } else if (*cie->augmentation == 'S') { | ||
704 | BUG(); | ||
705 | } else { | ||
706 | /* | ||
707 | * Unknown augmentation. Assume | ||
708 | * 'z' augmentation. | ||
709 | */ | ||
710 | p = cie->initial_instructions; | ||
711 | BUG_ON(!p); | ||
712 | break; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | cie->initial_instructions = p; | ||
717 | cie->instructions_end = end; | ||
718 | |||
719 | /* Add to list */ | ||
720 | spin_lock_irqsave(&dwarf_cie_lock, flags); | ||
721 | list_add_tail(&cie->link, &dwarf_cie_list); | ||
722 | spin_unlock_irqrestore(&dwarf_cie_lock, flags); | ||
723 | |||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | static int dwarf_parse_fde(void *entry, u32 entry_type, | ||
728 | void *start, unsigned long len) | ||
729 | { | ||
730 | struct dwarf_fde *fde; | ||
731 | struct dwarf_cie *cie; | ||
732 | unsigned long flags; | ||
733 | int count; | ||
734 | void *p = start; | ||
735 | |||
736 | fde = kzalloc(sizeof(*fde), GFP_KERNEL); | ||
737 | if (!fde) | ||
738 | return -ENOMEM; | ||
739 | |||
740 | fde->length = len; | ||
741 | |||
742 | /* | ||
743 | * In a .eh_frame section the CIE pointer is the | ||
744 | * delta between the address within the FDE | ||
745 | */ | ||
746 | fde->cie_pointer = (unsigned long)(p - entry_type - 4); | ||
747 | |||
748 | cie = dwarf_lookup_cie(fde->cie_pointer); | ||
749 | fde->cie = cie; | ||
750 | |||
751 | if (cie->encoding) | ||
752 | count = dwarf_read_encoded_value(p, &fde->initial_location, | ||
753 | cie->encoding); | ||
754 | else | ||
755 | count = dwarf_read_addr(p, &fde->initial_location); | ||
756 | |||
757 | p += count; | ||
758 | |||
759 | if (cie->encoding) | ||
760 | count = dwarf_read_encoded_value(p, &fde->address_range, | ||
761 | cie->encoding & 0x0f); | ||
762 | else | ||
763 | count = dwarf_read_addr(p, &fde->address_range); | ||
764 | |||
765 | p += count; | ||
766 | |||
767 | if (fde->cie->flags & DWARF_CIE_Z_AUGMENTATION) { | ||
768 | unsigned int length; | ||
769 | count = dwarf_read_uleb128(p, &length); | ||
770 | p += count + length; | ||
771 | } | ||
772 | |||
773 | /* Call frame instructions. */ | ||
774 | fde->instructions = p; | ||
775 | fde->end = start + len; | ||
776 | |||
777 | /* Add to list. */ | ||
778 | spin_lock_irqsave(&dwarf_fde_lock, flags); | ||
779 | list_add_tail(&fde->link, &dwarf_fde_list); | ||
780 | spin_unlock_irqrestore(&dwarf_fde_lock, flags); | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | static void dwarf_unwinder_dump(struct task_struct *task, struct pt_regs *regs, | ||
786 | unsigned long *sp, | ||
787 | const struct stacktrace_ops *ops, void *data) | ||
788 | { | ||
789 | struct dwarf_frame *frame; | ||
790 | |||
791 | frame = dwarf_unwind_stack(0, NULL); | ||
792 | |||
793 | while (frame && frame->return_addr) { | ||
794 | ops->address(data, frame->return_addr, 1); | ||
795 | frame = frame->next; | ||
796 | } | ||
797 | } | ||
798 | |||
799 | static struct unwinder dwarf_unwinder = { | ||
800 | .name = "dwarf-unwinder", | ||
801 | .dump = dwarf_unwinder_dump, | ||
802 | .rating = 150, | ||
803 | }; | ||
804 | |||
805 | static void dwarf_unwinder_cleanup(void) | ||
806 | { | ||
807 | struct dwarf_cie *cie, *m; | ||
808 | struct dwarf_fde *fde, *n; | ||
809 | unsigned long flags; | ||
810 | |||
811 | /* | ||
812 | * Deallocate all the memory allocated for the DWARF unwinder. | ||
813 | * Traverse all the FDE/CIE lists and remove and free all the | ||
814 | * memory associated with those data structures. | ||
815 | */ | ||
816 | spin_lock_irqsave(&dwarf_cie_lock, flags); | ||
817 | list_for_each_entry_safe(cie, m, &dwarf_cie_list, link) | ||
818 | kfree(cie); | ||
819 | spin_unlock_irqrestore(&dwarf_cie_lock, flags); | ||
820 | |||
821 | spin_lock_irqsave(&dwarf_fde_lock, flags); | ||
822 | list_for_each_entry_safe(fde, n, &dwarf_fde_list, link) | ||
823 | kfree(fde); | ||
824 | spin_unlock_irqrestore(&dwarf_fde_lock, flags); | ||
825 | } | ||
826 | |||
827 | /** | ||
828 | * dwarf_unwinder_init - initialise the dwarf unwinder | ||
829 | * | ||
830 | * Build the data structures describing the .dwarf_frame section to | ||
831 | * make it easier to lookup CIE and FDE entries. Because the | ||
832 | * .eh_frame section is packed as tightly as possible it is not | ||
833 | * easy to lookup the FDE for a given PC, so we build a list of FDE | ||
834 | * and CIE entries that make it easier. | ||
835 | */ | ||
836 | void dwarf_unwinder_init(void) | ||
837 | { | ||
838 | u32 entry_type; | ||
839 | void *p, *entry; | ||
840 | int count, err; | ||
841 | unsigned long len; | ||
842 | unsigned int c_entries, f_entries; | ||
843 | unsigned char *end; | ||
844 | INIT_LIST_HEAD(&dwarf_cie_list); | ||
845 | INIT_LIST_HEAD(&dwarf_fde_list); | ||
846 | |||
847 | c_entries = 0; | ||
848 | f_entries = 0; | ||
849 | entry = &__start_eh_frame; | ||
850 | |||
851 | while ((char *)entry < __stop_eh_frame) { | ||
852 | p = entry; | ||
853 | |||
854 | count = dwarf_entry_len(p, &len); | ||
855 | if (count == 0) { | ||
856 | /* | ||
857 | * We read a bogus length field value. There is | ||
858 | * nothing we can do here apart from disabling | ||
859 | * the DWARF unwinder. We can't even skip this | ||
860 | * entry and move to the next one because 'len' | ||
861 | * tells us where our next entry is. | ||
862 | */ | ||
863 | goto out; | ||
864 | } else | ||
865 | p += count; | ||
866 | |||
867 | /* initial length does not include itself */ | ||
868 | end = p + len; | ||
869 | |||
870 | entry_type = get_unaligned((u32 *)p); | ||
871 | p += 4; | ||
872 | |||
873 | if (entry_type == DW_EH_FRAME_CIE) { | ||
874 | err = dwarf_parse_cie(entry, p, len, end); | ||
875 | if (err < 0) | ||
876 | goto out; | ||
877 | else | ||
878 | c_entries++; | ||
879 | } else { | ||
880 | err = dwarf_parse_fde(entry, entry_type, p, len); | ||
881 | if (err < 0) | ||
882 | goto out; | ||
883 | else | ||
884 | f_entries++; | ||
885 | } | ||
886 | |||
887 | entry = (char *)entry + len + 4; | ||
888 | } | ||
889 | |||
890 | printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n", | ||
891 | c_entries, f_entries); | ||
892 | |||
893 | err = unwinder_register(&dwarf_unwinder); | ||
894 | if (err) | ||
895 | goto out; | ||
896 | |||
897 | return; | ||
898 | |||
899 | out: | ||
900 | printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err); | ||
901 | dwarf_unwinder_cleanup(); | ||
902 | } | ||
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c index a952dcf9999d..81a46145ffa5 100644 --- a/arch/sh/kernel/early_printk.c +++ b/arch/sh/kernel/early_printk.c | |||
@@ -134,7 +134,7 @@ static void scif_sercon_init(char *s) | |||
134 | sci_out(&scif_port, SCFCR, 0x0030); /* TTRG=b'11 */ | 134 | sci_out(&scif_port, SCFCR, 0x0030); /* TTRG=b'11 */ |
135 | sci_out(&scif_port, SCSCR, 0x0030); /* TE, RE */ | 135 | sci_out(&scif_port, SCSCR, 0x0030); /* TE, RE */ |
136 | } | 136 | } |
137 | #elif defined(CONFIG_CPU_SH4) | 137 | #elif defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SH3) |
138 | #define DEFAULT_BAUD 115200 | 138 | #define DEFAULT_BAUD 115200 |
139 | /* | 139 | /* |
140 | * Simple SCIF init, primarily aimed at SH7750 and other similar SH-4 | 140 | * Simple SCIF init, primarily aimed at SH7750 and other similar SH-4 |
@@ -220,8 +220,7 @@ static int __init setup_early_printk(char *buf) | |||
220 | early_console = &scif_console; | 220 | early_console = &scif_console; |
221 | 221 | ||
222 | #if !defined(CONFIG_SH_STANDARD_BIOS) | 222 | #if !defined(CONFIG_SH_STANDARD_BIOS) |
223 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SUBTYPE_SH7720) || \ | 223 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SH3) |
224 | defined(CONFIG_CPU_SUBTYPE_SH7721) | ||
225 | scif_sercon_init(buf + 6); | 224 | scif_sercon_init(buf + 6); |
226 | #endif | 225 | #endif |
227 | #endif | 226 | #endif |
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index d62359cfbbe2..e63178fefb9b 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S | |||
@@ -43,9 +43,10 @@ | |||
43 | * syscall # | 43 | * syscall # |
44 | * | 44 | * |
45 | */ | 45 | */ |
46 | #include <asm/dwarf.h> | ||
46 | 47 | ||
47 | #if defined(CONFIG_PREEMPT) | 48 | #if defined(CONFIG_PREEMPT) |
48 | # define preempt_stop() cli | 49 | # define preempt_stop() cli ; TRACE_IRQS_OFF |
49 | #else | 50 | #else |
50 | # define preempt_stop() | 51 | # define preempt_stop() |
51 | # define resume_kernel __restore_all | 52 | # define resume_kernel __restore_all |
@@ -55,11 +56,7 @@ | |||
55 | .align 2 | 56 | .align 2 |
56 | ENTRY(exception_error) | 57 | ENTRY(exception_error) |
57 | ! | 58 | ! |
58 | #ifdef CONFIG_TRACE_IRQFLAGS | 59 | TRACE_IRQS_ON |
59 | mov.l 2f, r0 | ||
60 | jsr @r0 | ||
61 | nop | ||
62 | #endif | ||
63 | sti | 60 | sti |
64 | mov.l 1f, r0 | 61 | mov.l 1f, r0 |
65 | jmp @r0 | 62 | jmp @r0 |
@@ -67,22 +64,28 @@ ENTRY(exception_error) | |||
67 | 64 | ||
68 | .align 2 | 65 | .align 2 |
69 | 1: .long do_exception_error | 66 | 1: .long do_exception_error |
70 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
71 | 2: .long trace_hardirqs_on | ||
72 | #endif | ||
73 | 67 | ||
74 | .align 2 | 68 | .align 2 |
75 | ret_from_exception: | 69 | ret_from_exception: |
70 | CFI_STARTPROC simple | ||
71 | CFI_DEF_CFA r14, 0 | ||
72 | CFI_REL_OFFSET 17, 64 | ||
73 | CFI_REL_OFFSET 15, 0 | ||
74 | CFI_REL_OFFSET 14, 56 | ||
76 | preempt_stop() | 75 | preempt_stop() |
77 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
78 | mov.l 4f, r0 | ||
79 | jsr @r0 | ||
80 | nop | ||
81 | #endif | ||
82 | ENTRY(ret_from_irq) | 76 | ENTRY(ret_from_irq) |
83 | ! | 77 | ! |
84 | mov #OFF_SR, r0 | 78 | mov #OFF_SR, r0 |
85 | mov.l @(r0,r15), r0 ! get status register | 79 | mov.l @(r0,r15), r0 ! get status register |
80 | |||
81 | shlr2 r0 | ||
82 | and #0x3c, r0 | ||
83 | cmp/eq #0x3c, r0 | ||
84 | bt 9f | ||
85 | TRACE_IRQS_ON | ||
86 | 9: | ||
87 | mov #OFF_SR, r0 | ||
88 | mov.l @(r0,r15), r0 ! get status register | ||
86 | shll r0 | 89 | shll r0 |
87 | shll r0 ! kernel space? | 90 | shll r0 ! kernel space? |
88 | get_current_thread_info r8, r0 | 91 | get_current_thread_info r8, r0 |
@@ -125,13 +128,9 @@ noresched: | |||
125 | ENTRY(resume_userspace) | 128 | ENTRY(resume_userspace) |
126 | ! r8: current_thread_info | 129 | ! r8: current_thread_info |
127 | cli | 130 | cli |
128 | #ifdef CONFIG_TRACE_IRQFLAGS | 131 | TRACE_IRQS_OfF |
129 | mov.l 5f, r0 | ||
130 | jsr @r0 | ||
131 | nop | ||
132 | #endif | ||
133 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | 132 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags |
134 | tst #_TIF_WORK_MASK, r0 | 133 | tst #(_TIF_WORK_MASK & 0xff), r0 |
135 | bt/s __restore_all | 134 | bt/s __restore_all |
136 | tst #_TIF_NEED_RESCHED, r0 | 135 | tst #_TIF_NEED_RESCHED, r0 |
137 | 136 | ||
@@ -156,14 +155,10 @@ work_resched: | |||
156 | jsr @r1 ! schedule | 155 | jsr @r1 ! schedule |
157 | nop | 156 | nop |
158 | cli | 157 | cli |
159 | #ifdef CONFIG_TRACE_IRQFLAGS | 158 | TRACE_IRQS_OFF |
160 | mov.l 5f, r0 | ||
161 | jsr @r0 | ||
162 | nop | ||
163 | #endif | ||
164 | ! | 159 | ! |
165 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | 160 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags |
166 | tst #_TIF_WORK_MASK, r0 | 161 | tst #(_TIF_WORK_MASK & 0xff), r0 |
167 | bt __restore_all | 162 | bt __restore_all |
168 | bra work_pending | 163 | bra work_pending |
169 | tst #_TIF_NEED_RESCHED, r0 | 164 | tst #_TIF_NEED_RESCHED, r0 |
@@ -172,23 +167,15 @@ work_resched: | |||
172 | 1: .long schedule | 167 | 1: .long schedule |
173 | 2: .long do_notify_resume | 168 | 2: .long do_notify_resume |
174 | 3: .long resume_userspace | 169 | 3: .long resume_userspace |
175 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
176 | 4: .long trace_hardirqs_on | ||
177 | 5: .long trace_hardirqs_off | ||
178 | #endif | ||
179 | 170 | ||
180 | .align 2 | 171 | .align 2 |
181 | syscall_exit_work: | 172 | syscall_exit_work: |
182 | ! r0: current_thread_info->flags | 173 | ! r0: current_thread_info->flags |
183 | ! r8: current_thread_info | 174 | ! r8: current_thread_info |
184 | tst #_TIF_WORK_SYSCALL_MASK, r0 | 175 | tst #(_TIF_WORK_SYSCALL_MASK & 0xff), r0 |
185 | bt/s work_pending | 176 | bt/s work_pending |
186 | tst #_TIF_NEED_RESCHED, r0 | 177 | tst #_TIF_NEED_RESCHED, r0 |
187 | #ifdef CONFIG_TRACE_IRQFLAGS | 178 | TRACE_IRQS_ON |
188 | mov.l 5f, r0 | ||
189 | jsr @r0 | ||
190 | nop | ||
191 | #endif | ||
192 | sti | 179 | sti |
193 | mov r15, r4 | 180 | mov r15, r4 |
194 | mov.l 8f, r0 ! do_syscall_trace_leave | 181 | mov.l 8f, r0 ! do_syscall_trace_leave |
@@ -259,6 +246,7 @@ debug_trap: | |||
259 | nop | 246 | nop |
260 | bra __restore_all | 247 | bra __restore_all |
261 | nop | 248 | nop |
249 | CFI_ENDPROC | ||
262 | 250 | ||
263 | .align 2 | 251 | .align 2 |
264 | 1: .long debug_trap_table | 252 | 1: .long debug_trap_table |
@@ -304,6 +292,7 @@ ret_from_fork: | |||
304 | * system calls and debug traps through their respective jump tables. | 292 | * system calls and debug traps through their respective jump tables. |
305 | */ | 293 | */ |
306 | ENTRY(system_call) | 294 | ENTRY(system_call) |
295 | setup_frame_reg | ||
307 | #if !defined(CONFIG_CPU_SH2) | 296 | #if !defined(CONFIG_CPU_SH2) |
308 | mov.l 1f, r9 | 297 | mov.l 1f, r9 |
309 | mov.l @r9, r8 ! Read from TRA (Trap Address) Register | 298 | mov.l @r9, r8 ! Read from TRA (Trap Address) Register |
@@ -321,18 +310,18 @@ ENTRY(system_call) | |||
321 | bt/s debug_trap ! it's a debug trap.. | 310 | bt/s debug_trap ! it's a debug trap.. |
322 | nop | 311 | nop |
323 | 312 | ||
324 | #ifdef CONFIG_TRACE_IRQFLAGS | 313 | TRACE_IRQS_ON |
325 | mov.l 5f, r10 | ||
326 | jsr @r10 | ||
327 | nop | ||
328 | #endif | ||
329 | sti | 314 | sti |
330 | 315 | ||
331 | ! | 316 | ! |
332 | get_current_thread_info r8, r10 | 317 | get_current_thread_info r8, r10 |
333 | mov.l @(TI_FLAGS,r8), r8 | 318 | mov.l @(TI_FLAGS,r8), r8 |
334 | mov #_TIF_WORK_SYSCALL_MASK, r10 | 319 | mov #(_TIF_WORK_SYSCALL_MASK & 0xff), r10 |
320 | mov #(_TIF_WORK_SYSCALL_MASK >> 8), r9 | ||
335 | tst r10, r8 | 321 | tst r10, r8 |
322 | shll8 r9 | ||
323 | bf syscall_trace_entry | ||
324 | tst r9, r8 | ||
336 | bf syscall_trace_entry | 325 | bf syscall_trace_entry |
337 | ! | 326 | ! |
338 | mov.l 2f, r8 ! Number of syscalls | 327 | mov.l 2f, r8 ! Number of syscalls |
@@ -351,15 +340,15 @@ syscall_call: | |||
351 | ! | 340 | ! |
352 | syscall_exit: | 341 | syscall_exit: |
353 | cli | 342 | cli |
354 | #ifdef CONFIG_TRACE_IRQFLAGS | 343 | TRACE_IRQS_OFF |
355 | mov.l 6f, r0 | ||
356 | jsr @r0 | ||
357 | nop | ||
358 | #endif | ||
359 | ! | 344 | ! |
360 | get_current_thread_info r8, r0 | 345 | get_current_thread_info r8, r0 |
361 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags | 346 | mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags |
362 | tst #_TIF_ALLWORK_MASK, r0 | 347 | tst #(_TIF_ALLWORK_MASK & 0xff), r0 |
348 | mov #(_TIF_ALLWORK_MASK >> 8), r1 | ||
349 | bf syscall_exit_work | ||
350 | shlr8 r0 | ||
351 | tst r0, r1 | ||
363 | bf syscall_exit_work | 352 | bf syscall_exit_work |
364 | bra __restore_all | 353 | bra __restore_all |
365 | nop | 354 | nop |
@@ -369,9 +358,5 @@ syscall_exit: | |||
369 | #endif | 358 | #endif |
370 | 2: .long NR_syscalls | 359 | 2: .long NR_syscalls |
371 | 3: .long sys_call_table | 360 | 3: .long sys_call_table |
372 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
373 | 5: .long trace_hardirqs_on | ||
374 | 6: .long trace_hardirqs_off | ||
375 | #endif | ||
376 | 7: .long do_syscall_trace_enter | 361 | 7: .long do_syscall_trace_enter |
377 | 8: .long do_syscall_trace_leave | 362 | 8: .long do_syscall_trace_leave |
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c index 066f37dc32a9..6647dfcb781d 100644 --- a/arch/sh/kernel/ftrace.c +++ b/arch/sh/kernel/ftrace.c | |||
@@ -16,9 +16,13 @@ | |||
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/kernel.h> | ||
19 | #include <asm/ftrace.h> | 20 | #include <asm/ftrace.h> |
20 | #include <asm/cacheflush.h> | 21 | #include <asm/cacheflush.h> |
22 | #include <asm/unistd.h> | ||
23 | #include <trace/syscall.h> | ||
21 | 24 | ||
25 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
22 | static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE]; | 26 | static unsigned char ftrace_replaced_code[MCOUNT_INSN_SIZE]; |
23 | 27 | ||
24 | static unsigned char ftrace_nop[4]; | 28 | static unsigned char ftrace_nop[4]; |
@@ -131,3 +135,189 @@ int __init ftrace_dyn_arch_init(void *data) | |||
131 | 135 | ||
132 | return 0; | 136 | return 0; |
133 | } | 137 | } |
138 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
139 | |||
140 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
141 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
142 | extern void ftrace_graph_call(void); | ||
143 | |||
144 | static int ftrace_mod(unsigned long ip, unsigned long old_addr, | ||
145 | unsigned long new_addr) | ||
146 | { | ||
147 | unsigned char code[MCOUNT_INSN_SIZE]; | ||
148 | |||
149 | if (probe_kernel_read(code, (void *)ip, MCOUNT_INSN_SIZE)) | ||
150 | return -EFAULT; | ||
151 | |||
152 | if (old_addr != __raw_readl((unsigned long *)code)) | ||
153 | return -EINVAL; | ||
154 | |||
155 | __raw_writel(new_addr, ip); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | int ftrace_enable_ftrace_graph_caller(void) | ||
160 | { | ||
161 | unsigned long ip, old_addr, new_addr; | ||
162 | |||
163 | ip = (unsigned long)(&ftrace_graph_call) + GRAPH_INSN_OFFSET; | ||
164 | old_addr = (unsigned long)(&skip_trace); | ||
165 | new_addr = (unsigned long)(&ftrace_graph_caller); | ||
166 | |||
167 | return ftrace_mod(ip, old_addr, new_addr); | ||
168 | } | ||
169 | |||
170 | int ftrace_disable_ftrace_graph_caller(void) | ||
171 | { | ||
172 | unsigned long ip, old_addr, new_addr; | ||
173 | |||
174 | ip = (unsigned long)(&ftrace_graph_call) + GRAPH_INSN_OFFSET; | ||
175 | old_addr = (unsigned long)(&ftrace_graph_caller); | ||
176 | new_addr = (unsigned long)(&skip_trace); | ||
177 | |||
178 | return ftrace_mod(ip, old_addr, new_addr); | ||
179 | } | ||
180 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
181 | |||
182 | /* | ||
183 | * Hook the return address and push it in the stack of return addrs | ||
184 | * in the current thread info. | ||
185 | * | ||
186 | * This is the main routine for the function graph tracer. The function | ||
187 | * graph tracer essentially works like this: | ||
188 | * | ||
189 | * parent is the stack address containing self_addr's return address. | ||
190 | * We pull the real return address out of parent and store it in | ||
191 | * current's ret_stack. Then, we replace the return address on the stack | ||
192 | * with the address of return_to_handler. self_addr is the function that | ||
193 | * called mcount. | ||
194 | * | ||
195 | * When self_addr returns, it will jump to return_to_handler which calls | ||
196 | * ftrace_return_to_handler. ftrace_return_to_handler will pull the real | ||
197 | * return address off of current's ret_stack and jump to it. | ||
198 | */ | ||
199 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) | ||
200 | { | ||
201 | unsigned long old; | ||
202 | int faulted, err; | ||
203 | struct ftrace_graph_ent trace; | ||
204 | unsigned long return_hooker = (unsigned long)&return_to_handler; | ||
205 | |||
206 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
207 | return; | ||
208 | |||
209 | /* | ||
210 | * Protect against fault, even if it shouldn't | ||
211 | * happen. This tool is too much intrusive to | ||
212 | * ignore such a protection. | ||
213 | */ | ||
214 | __asm__ __volatile__( | ||
215 | "1: \n\t" | ||
216 | "mov.l @%2, %0 \n\t" | ||
217 | "2: \n\t" | ||
218 | "mov.l %3, @%2 \n\t" | ||
219 | "mov #0, %1 \n\t" | ||
220 | "3: \n\t" | ||
221 | ".section .fixup, \"ax\" \n\t" | ||
222 | "4: \n\t" | ||
223 | "mov.l 5f, %0 \n\t" | ||
224 | "jmp @%0 \n\t" | ||
225 | " mov #1, %1 \n\t" | ||
226 | ".balign 4 \n\t" | ||
227 | "5: .long 3b \n\t" | ||
228 | ".previous \n\t" | ||
229 | ".section __ex_table,\"a\" \n\t" | ||
230 | ".long 1b, 4b \n\t" | ||
231 | ".long 2b, 4b \n\t" | ||
232 | ".previous \n\t" | ||
233 | : "=&r" (old), "=r" (faulted) | ||
234 | : "r" (parent), "r" (return_hooker) | ||
235 | ); | ||
236 | |||
237 | if (unlikely(faulted)) { | ||
238 | ftrace_graph_stop(); | ||
239 | WARN_ON(1); | ||
240 | return; | ||
241 | } | ||
242 | |||
243 | err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0); | ||
244 | if (err == -EBUSY) { | ||
245 | __raw_writel(old, parent); | ||
246 | return; | ||
247 | } | ||
248 | |||
249 | trace.func = self_addr; | ||
250 | |||
251 | /* Only trace if the calling function expects to */ | ||
252 | if (!ftrace_graph_entry(&trace)) { | ||
253 | current->curr_ret_stack--; | ||
254 | __raw_writel(old, parent); | ||
255 | } | ||
256 | } | ||
257 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
258 | |||
259 | #ifdef CONFIG_FTRACE_SYSCALLS | ||
260 | |||
261 | extern unsigned long __start_syscalls_metadata[]; | ||
262 | extern unsigned long __stop_syscalls_metadata[]; | ||
263 | extern unsigned long *sys_call_table; | ||
264 | |||
265 | static struct syscall_metadata **syscalls_metadata; | ||
266 | |||
267 | static struct syscall_metadata *find_syscall_meta(unsigned long *syscall) | ||
268 | { | ||
269 | struct syscall_metadata *start; | ||
270 | struct syscall_metadata *stop; | ||
271 | char str[KSYM_SYMBOL_LEN]; | ||
272 | |||
273 | |||
274 | start = (struct syscall_metadata *)__start_syscalls_metadata; | ||
275 | stop = (struct syscall_metadata *)__stop_syscalls_metadata; | ||
276 | kallsyms_lookup((unsigned long) syscall, NULL, NULL, NULL, str); | ||
277 | |||
278 | for ( ; start < stop; start++) { | ||
279 | if (start->name && !strcmp(start->name, str)) | ||
280 | return start; | ||
281 | } | ||
282 | |||
283 | return NULL; | ||
284 | } | ||
285 | |||
286 | #define FTRACE_SYSCALL_MAX (NR_syscalls - 1) | ||
287 | |||
288 | struct syscall_metadata *syscall_nr_to_meta(int nr) | ||
289 | { | ||
290 | if (!syscalls_metadata || nr >= FTRACE_SYSCALL_MAX || nr < 0) | ||
291 | return NULL; | ||
292 | |||
293 | return syscalls_metadata[nr]; | ||
294 | } | ||
295 | |||
296 | void arch_init_ftrace_syscalls(void) | ||
297 | { | ||
298 | int i; | ||
299 | struct syscall_metadata *meta; | ||
300 | unsigned long **psys_syscall_table = &sys_call_table; | ||
301 | static atomic_t refs; | ||
302 | |||
303 | if (atomic_inc_return(&refs) != 1) | ||
304 | goto end; | ||
305 | |||
306 | syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * | ||
307 | FTRACE_SYSCALL_MAX, GFP_KERNEL); | ||
308 | if (!syscalls_metadata) { | ||
309 | WARN_ON(1); | ||
310 | return; | ||
311 | } | ||
312 | |||
313 | for (i = 0; i < FTRACE_SYSCALL_MAX; i++) { | ||
314 | meta = find_syscall_meta(psys_syscall_table[i]); | ||
315 | syscalls_metadata[i] = meta; | ||
316 | } | ||
317 | return; | ||
318 | |||
319 | /* Paranoid: avoid overflow */ | ||
320 | end: | ||
321 | atomic_dec(&refs); | ||
322 | } | ||
323 | #endif /* CONFIG_FTRACE_SYSCALLS */ | ||
diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c index 77dfecb64373..e27a19e1f46e 100644 --- a/arch/sh/kernel/io_trapped.c +++ b/arch/sh/kernel/io_trapped.c | |||
@@ -112,14 +112,15 @@ void __iomem *match_trapped_io_handler(struct list_head *list, | |||
112 | struct trapped_io *tiop; | 112 | struct trapped_io *tiop; |
113 | struct resource *res; | 113 | struct resource *res; |
114 | int k, len; | 114 | int k, len; |
115 | unsigned long flags; | ||
115 | 116 | ||
116 | spin_lock_irq(&trapped_lock); | 117 | spin_lock_irqsave(&trapped_lock, flags); |
117 | list_for_each_entry(tiop, list, list) { | 118 | list_for_each_entry(tiop, list, list) { |
118 | voffs = 0; | 119 | voffs = 0; |
119 | for (k = 0; k < tiop->num_resources; k++) { | 120 | for (k = 0; k < tiop->num_resources; k++) { |
120 | res = tiop->resource + k; | 121 | res = tiop->resource + k; |
121 | if (res->start == offset) { | 122 | if (res->start == offset) { |
122 | spin_unlock_irq(&trapped_lock); | 123 | spin_unlock_irqrestore(&trapped_lock, flags); |
123 | return tiop->virt_base + voffs; | 124 | return tiop->virt_base + voffs; |
124 | } | 125 | } |
125 | 126 | ||
@@ -127,7 +128,7 @@ void __iomem *match_trapped_io_handler(struct list_head *list, | |||
127 | voffs += roundup(len, PAGE_SIZE); | 128 | voffs += roundup(len, PAGE_SIZE); |
128 | } | 129 | } |
129 | } | 130 | } |
130 | spin_unlock_irq(&trapped_lock); | 131 | spin_unlock_irqrestore(&trapped_lock, flags); |
131 | return NULL; | 132 | return NULL; |
132 | } | 133 | } |
133 | EXPORT_SYMBOL_GPL(match_trapped_io_handler); | 134 | EXPORT_SYMBOL_GPL(match_trapped_io_handler); |
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 3d09062f4682..2bb43dc74f22 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
15 | #include <asm/machvec.h> | 15 | #include <asm/machvec.h> |
16 | #include <asm/uaccess.h> | 16 | #include <asm/uaccess.h> |
17 | #include <asm/dwarf.h> | ||
17 | #include <asm/thread_info.h> | 18 | #include <asm/thread_info.h> |
18 | #include <cpu/mmu_context.h> | 19 | #include <cpu/mmu_context.h> |
19 | 20 | ||
@@ -114,23 +115,6 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs) | |||
114 | #endif | 115 | #endif |
115 | 116 | ||
116 | irq_enter(); | 117 | irq_enter(); |
117 | |||
118 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | ||
119 | /* Debugging check for stack overflow: is there less than 1KB free? */ | ||
120 | { | ||
121 | long sp; | ||
122 | |||
123 | __asm__ __volatile__ ("and r15, %0" : | ||
124 | "=r" (sp) : "0" (THREAD_SIZE - 1)); | ||
125 | |||
126 | if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) { | ||
127 | printk("do_IRQ: stack overflow: %ld\n", | ||
128 | sp - sizeof(struct thread_info)); | ||
129 | dump_stack(); | ||
130 | } | ||
131 | } | ||
132 | #endif | ||
133 | |||
134 | irq = irq_demux(intc_evt2irq(irq)); | 118 | irq = irq_demux(intc_evt2irq(irq)); |
135 | 119 | ||
136 | #ifdef CONFIG_IRQSTACKS | 120 | #ifdef CONFIG_IRQSTACKS |
@@ -278,6 +262,9 @@ void __init init_IRQ(void) | |||
278 | sh_mv.mv_init_irq(); | 262 | sh_mv.mv_init_irq(); |
279 | 263 | ||
280 | irq_ctx_init(smp_processor_id()); | 264 | irq_ctx_init(smp_processor_id()); |
265 | |||
266 | /* This needs to be early, but not too early.. */ | ||
267 | dwarf_unwinder_init(); | ||
281 | } | 268 | } |
282 | 269 | ||
283 | #ifdef CONFIG_SPARSE_IRQ | 270 | #ifdef CONFIG_SPARSE_IRQ |
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 92d7740faab1..9fee977f176b 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/tick.h> | 23 | #include <linux/tick.h> |
24 | #include <linux/reboot.h> | 24 | #include <linux/reboot.h> |
25 | #include <linux/fs.h> | 25 | #include <linux/fs.h> |
26 | #include <linux/ftrace.h> | ||
26 | #include <linux/preempt.h> | 27 | #include <linux/preempt.h> |
27 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
28 | #include <asm/mmu_context.h> | 29 | #include <asm/mmu_context.h> |
@@ -264,8 +265,8 @@ static void ubc_set_tracing(int asid, unsigned long pc) | |||
264 | * switch_to(x,y) should switch tasks from x to y. | 265 | * switch_to(x,y) should switch tasks from x to y. |
265 | * | 266 | * |
266 | */ | 267 | */ |
267 | struct task_struct *__switch_to(struct task_struct *prev, | 268 | __notrace_funcgraph struct task_struct * |
268 | struct task_struct *next) | 269 | __switch_to(struct task_struct *prev, struct task_struct *next) |
269 | { | 270 | { |
270 | #if defined(CONFIG_SH_FPU) | 271 | #if defined(CONFIG_SH_FPU) |
271 | unlazy_fpu(prev, task_pt_regs(prev)); | 272 | unlazy_fpu(prev, task_pt_regs(prev)); |
diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 3392e835a374..c198eceaee94 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c | |||
@@ -34,6 +34,8 @@ | |||
34 | #include <asm/syscalls.h> | 34 | #include <asm/syscalls.h> |
35 | #include <asm/fpu.h> | 35 | #include <asm/fpu.h> |
36 | 36 | ||
37 | #include <trace/syscall.h> | ||
38 | |||
37 | /* | 39 | /* |
38 | * This routine will get a word off of the process kernel stack. | 40 | * This routine will get a word off of the process kernel stack. |
39 | */ | 41 | */ |
@@ -459,6 +461,9 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs) | |||
459 | */ | 461 | */ |
460 | ret = -1L; | 462 | ret = -1L; |
461 | 463 | ||
464 | if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) | ||
465 | ftrace_syscall_enter(regs); | ||
466 | |||
462 | if (unlikely(current->audit_context)) | 467 | if (unlikely(current->audit_context)) |
463 | audit_syscall_entry(audit_arch(), regs->regs[3], | 468 | audit_syscall_entry(audit_arch(), regs->regs[3], |
464 | regs->regs[4], regs->regs[5], | 469 | regs->regs[4], regs->regs[5], |
@@ -475,6 +480,9 @@ asmlinkage void do_syscall_trace_leave(struct pt_regs *regs) | |||
475 | audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]), | 480 | audit_syscall_exit(AUDITSC_RESULT(regs->regs[0]), |
476 | regs->regs[0]); | 481 | regs->regs[0]); |
477 | 482 | ||
483 | if (unlikely(test_thread_flag(TIF_SYSCALL_FTRACE))) | ||
484 | ftrace_syscall_exit(regs); | ||
485 | |||
478 | step = test_thread_flag(TIF_SINGLESTEP); | 486 | step = test_thread_flag(TIF_SINGLESTEP); |
479 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) | 487 | if (step || test_thread_flag(TIF_SYSCALL_TRACE)) |
480 | tracehook_report_syscall_exit(regs, step); | 488 | tracehook_report_syscall_exit(regs, step); |
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index dd38338553ef..ceb409bf7741 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/lmb.h> | ||
33 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
34 | #include <asm/io.h> | 35 | #include <asm/io.h> |
35 | #include <asm/page.h> | 36 | #include <asm/page.h> |
@@ -233,39 +234,45 @@ void __init __add_active_range(unsigned int nid, unsigned long start_pfn, | |||
233 | void __init setup_bootmem_allocator(unsigned long free_pfn) | 234 | void __init setup_bootmem_allocator(unsigned long free_pfn) |
234 | { | 235 | { |
235 | unsigned long bootmap_size; | 236 | unsigned long bootmap_size; |
237 | unsigned long bootmap_pages, bootmem_paddr; | ||
238 | u64 total_pages = (lmb_end_of_DRAM() - __MEMORY_START) >> PAGE_SHIFT; | ||
239 | int i; | ||
240 | |||
241 | bootmap_pages = bootmem_bootmap_pages(total_pages); | ||
242 | |||
243 | bootmem_paddr = lmb_alloc(bootmap_pages << PAGE_SHIFT, PAGE_SIZE); | ||
236 | 244 | ||
237 | /* | 245 | /* |
238 | * Find a proper area for the bootmem bitmap. After this | 246 | * Find a proper area for the bootmem bitmap. After this |
239 | * bootstrap step all allocations (until the page allocator | 247 | * bootstrap step all allocations (until the page allocator |
240 | * is intact) must be done via bootmem_alloc(). | 248 | * is intact) must be done via bootmem_alloc(). |
241 | */ | 249 | */ |
242 | bootmap_size = init_bootmem_node(NODE_DATA(0), free_pfn, | 250 | bootmap_size = init_bootmem_node(NODE_DATA(0), |
251 | bootmem_paddr >> PAGE_SHIFT, | ||
243 | min_low_pfn, max_low_pfn); | 252 | min_low_pfn, max_low_pfn); |
244 | 253 | ||
245 | __add_active_range(0, min_low_pfn, max_low_pfn); | 254 | /* Add active regions with valid PFNs. */ |
246 | register_bootmem_low_pages(); | 255 | for (i = 0; i < lmb.memory.cnt; i++) { |
247 | 256 | unsigned long start_pfn, end_pfn; | |
248 | node_set_online(0); | 257 | start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT; |
258 | end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i); | ||
259 | __add_active_range(0, start_pfn, end_pfn); | ||
260 | } | ||
249 | 261 | ||
250 | /* | 262 | /* |
251 | * Reserve the kernel text and | 263 | * Add all physical memory to the bootmem map and mark each |
252 | * Reserve the bootmem bitmap. We do this in two steps (first step | 264 | * area as present. |
253 | * was init_bootmem()), because this catches the (definitely buggy) | ||
254 | * case of us accidentally initializing the bootmem allocator with | ||
255 | * an invalid RAM area. | ||
256 | */ | 265 | */ |
257 | reserve_bootmem(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET, | 266 | register_bootmem_low_pages(); |
258 | (PFN_PHYS(free_pfn) + bootmap_size + PAGE_SIZE - 1) - | ||
259 | (__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET), | ||
260 | BOOTMEM_DEFAULT); | ||
261 | 267 | ||
262 | /* | 268 | /* Reserve the sections we're already using. */ |
263 | * Reserve physical pages below CONFIG_ZERO_PAGE_OFFSET. | 269 | for (i = 0; i < lmb.reserved.cnt; i++) |
264 | */ | 270 | reserve_bootmem(lmb.reserved.region[i].base, |
265 | if (CONFIG_ZERO_PAGE_OFFSET != 0) | 271 | lmb_size_bytes(&lmb.reserved, i), |
266 | reserve_bootmem(__MEMORY_START, CONFIG_ZERO_PAGE_OFFSET, | ||
267 | BOOTMEM_DEFAULT); | 272 | BOOTMEM_DEFAULT); |
268 | 273 | ||
274 | node_set_online(0); | ||
275 | |||
269 | sparse_memory_present_with_active_regions(0); | 276 | sparse_memory_present_with_active_regions(0); |
270 | 277 | ||
271 | #ifdef CONFIG_BLK_DEV_INITRD | 278 | #ifdef CONFIG_BLK_DEV_INITRD |
@@ -296,12 +303,37 @@ void __init setup_bootmem_allocator(unsigned long free_pfn) | |||
296 | static void __init setup_memory(void) | 303 | static void __init setup_memory(void) |
297 | { | 304 | { |
298 | unsigned long start_pfn; | 305 | unsigned long start_pfn; |
306 | u64 base = min_low_pfn << PAGE_SHIFT; | ||
307 | u64 size = (max_low_pfn << PAGE_SHIFT) - base; | ||
299 | 308 | ||
300 | /* | 309 | /* |
301 | * Partially used pages are not usable - thus | 310 | * Partially used pages are not usable - thus |
302 | * we are rounding upwards: | 311 | * we are rounding upwards: |
303 | */ | 312 | */ |
304 | start_pfn = PFN_UP(__pa(_end)); | 313 | start_pfn = PFN_UP(__pa(_end)); |
314 | |||
315 | lmb_add(base, size); | ||
316 | |||
317 | /* | ||
318 | * Reserve the kernel text and | ||
319 | * Reserve the bootmem bitmap. We do this in two steps (first step | ||
320 | * was init_bootmem()), because this catches the (definitely buggy) | ||
321 | * case of us accidentally initializing the bootmem allocator with | ||
322 | * an invalid RAM area. | ||
323 | */ | ||
324 | lmb_reserve(__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET, | ||
325 | (PFN_PHYS(start_pfn) + PAGE_SIZE - 1) - | ||
326 | (__MEMORY_START + CONFIG_ZERO_PAGE_OFFSET)); | ||
327 | |||
328 | /* | ||
329 | * Reserve physical pages below CONFIG_ZERO_PAGE_OFFSET. | ||
330 | */ | ||
331 | if (CONFIG_ZERO_PAGE_OFFSET != 0) | ||
332 | lmb_reserve(__MEMORY_START, CONFIG_ZERO_PAGE_OFFSET); | ||
333 | |||
334 | lmb_analyze(); | ||
335 | lmb_dump_all(); | ||
336 | |||
305 | setup_bootmem_allocator(start_pfn); | 337 | setup_bootmem_allocator(start_pfn); |
306 | } | 338 | } |
307 | #else | 339 | #else |
@@ -402,6 +434,7 @@ void __init setup_arch(char **cmdline_p) | |||
402 | nodes_clear(node_online_map); | 434 | nodes_clear(node_online_map); |
403 | 435 | ||
404 | /* Setup bootmem with available RAM */ | 436 | /* Setup bootmem with available RAM */ |
437 | lmb_init(); | ||
405 | setup_memory(); | 438 | setup_memory(); |
406 | sparse_init(); | 439 | sparse_init(); |
407 | 440 | ||
diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c index fcc5de31f83b..cec610888e28 100644 --- a/arch/sh/kernel/sh_ksyms_32.c +++ b/arch/sh/kernel/sh_ksyms_32.c | |||
@@ -106,8 +106,8 @@ EXPORT_SYMBOL(flush_dcache_page); | |||
106 | EXPORT_SYMBOL(clear_user_page); | 106 | EXPORT_SYMBOL(clear_user_page); |
107 | #endif | 107 | #endif |
108 | 108 | ||
109 | #ifdef CONFIG_FUNCTION_TRACER | 109 | #ifdef CONFIG_MCOUNT |
110 | EXPORT_SYMBOL(mcount); | 110 | DECLARE_EXPORT(mcount); |
111 | #endif | 111 | #endif |
112 | EXPORT_SYMBOL(csum_partial); | 112 | EXPORT_SYMBOL(csum_partial); |
113 | EXPORT_SYMBOL(csum_partial_copy_generic); | 113 | EXPORT_SYMBOL(csum_partial_copy_generic); |
diff --git a/arch/sh/kernel/stacktrace.c b/arch/sh/kernel/stacktrace.c index 1a2a5eb76e41..c2e45c48409c 100644 --- a/arch/sh/kernel/stacktrace.c +++ b/arch/sh/kernel/stacktrace.c | |||
@@ -13,47 +13,93 @@ | |||
13 | #include <linux/stacktrace.h> | 13 | #include <linux/stacktrace.h> |
14 | #include <linux/thread_info.h> | 14 | #include <linux/thread_info.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <asm/unwinder.h> | ||
16 | #include <asm/ptrace.h> | 17 | #include <asm/ptrace.h> |
18 | #include <asm/stacktrace.h> | ||
19 | |||
20 | static void save_stack_warning(void *data, char *msg) | ||
21 | { | ||
22 | } | ||
23 | |||
24 | static void | ||
25 | save_stack_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
26 | { | ||
27 | } | ||
28 | |||
29 | static int save_stack_stack(void *data, char *name) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
17 | 33 | ||
18 | /* | 34 | /* |
19 | * Save stack-backtrace addresses into a stack_trace buffer. | 35 | * Save stack-backtrace addresses into a stack_trace buffer. |
20 | */ | 36 | */ |
37 | static void save_stack_address(void *data, unsigned long addr, int reliable) | ||
38 | { | ||
39 | struct stack_trace *trace = data; | ||
40 | |||
41 | if (!reliable) | ||
42 | return; | ||
43 | |||
44 | if (trace->skip > 0) { | ||
45 | trace->skip--; | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | if (trace->nr_entries < trace->max_entries) | ||
50 | trace->entries[trace->nr_entries++] = addr; | ||
51 | } | ||
52 | |||
53 | static const struct stacktrace_ops save_stack_ops = { | ||
54 | .warning = save_stack_warning, | ||
55 | .warning_symbol = save_stack_warning_symbol, | ||
56 | .stack = save_stack_stack, | ||
57 | .address = save_stack_address, | ||
58 | }; | ||
59 | |||
21 | void save_stack_trace(struct stack_trace *trace) | 60 | void save_stack_trace(struct stack_trace *trace) |
22 | { | 61 | { |
23 | unsigned long *sp = (unsigned long *)current_stack_pointer; | 62 | unsigned long *sp = (unsigned long *)current_stack_pointer; |
24 | 63 | ||
25 | while (!kstack_end(sp)) { | 64 | unwind_stack(current, NULL, sp, &save_stack_ops, trace); |
26 | unsigned long addr = *sp++; | 65 | if (trace->nr_entries < trace->max_entries) |
27 | 66 | trace->entries[trace->nr_entries++] = ULONG_MAX; | |
28 | if (__kernel_text_address(addr)) { | ||
29 | if (trace->skip > 0) | ||
30 | trace->skip--; | ||
31 | else | ||
32 | trace->entries[trace->nr_entries++] = addr; | ||
33 | if (trace->nr_entries >= trace->max_entries) | ||
34 | break; | ||
35 | } | ||
36 | } | ||
37 | } | 67 | } |
38 | EXPORT_SYMBOL_GPL(save_stack_trace); | 68 | EXPORT_SYMBOL_GPL(save_stack_trace); |
39 | 69 | ||
70 | static void | ||
71 | save_stack_address_nosched(void *data, unsigned long addr, int reliable) | ||
72 | { | ||
73 | struct stack_trace *trace = (struct stack_trace *)data; | ||
74 | |||
75 | if (!reliable) | ||
76 | return; | ||
77 | |||
78 | if (in_sched_functions(addr)) | ||
79 | return; | ||
80 | |||
81 | if (trace->skip > 0) { | ||
82 | trace->skip--; | ||
83 | return; | ||
84 | } | ||
85 | |||
86 | if (trace->nr_entries < trace->max_entries) | ||
87 | trace->entries[trace->nr_entries++] = addr; | ||
88 | } | ||
89 | |||
90 | static const struct stacktrace_ops save_stack_ops_nosched = { | ||
91 | .warning = save_stack_warning, | ||
92 | .warning_symbol = save_stack_warning_symbol, | ||
93 | .stack = save_stack_stack, | ||
94 | .address = save_stack_address_nosched, | ||
95 | }; | ||
96 | |||
40 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | 97 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) |
41 | { | 98 | { |
42 | unsigned long *sp = (unsigned long *)tsk->thread.sp; | 99 | unsigned long *sp = (unsigned long *)tsk->thread.sp; |
43 | 100 | ||
44 | while (!kstack_end(sp)) { | 101 | unwind_stack(current, NULL, sp, &save_stack_ops_nosched, trace); |
45 | unsigned long addr = *sp++; | 102 | if (trace->nr_entries < trace->max_entries) |
46 | 103 | trace->entries[trace->nr_entries++] = ULONG_MAX; | |
47 | if (__kernel_text_address(addr)) { | ||
48 | if (in_sched_functions(addr)) | ||
49 | break; | ||
50 | if (trace->skip > 0) | ||
51 | trace->skip--; | ||
52 | else | ||
53 | trace->entries[trace->nr_entries++] = addr; | ||
54 | if (trace->nr_entries >= trace->max_entries) | ||
55 | break; | ||
56 | } | ||
57 | } | ||
58 | } | 104 | } |
59 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | 105 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); |
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index 9b352a1e3fb4..7f95f479060f 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/smp.h> | 21 | #include <linux/smp.h> |
22 | #include <linux/rtc.h> | 22 | #include <linux/rtc.h> |
23 | #include <asm/clock.h> | 23 | #include <asm/clock.h> |
24 | #include <asm/hwblk.h> | ||
24 | #include <asm/rtc.h> | 25 | #include <asm/rtc.h> |
25 | 26 | ||
26 | /* Dummy RTC ops */ | 27 | /* Dummy RTC ops */ |
@@ -91,11 +92,27 @@ module_init(rtc_generic_init); | |||
91 | 92 | ||
92 | void (*board_time_init)(void); | 93 | void (*board_time_init)(void); |
93 | 94 | ||
95 | static void __init sh_late_time_init(void) | ||
96 | { | ||
97 | /* | ||
98 | * Make sure all compiled-in early timers register themselves. | ||
99 | * | ||
100 | * Run probe() for two "earlytimer" devices, these will be the | ||
101 | * clockevents and clocksource devices respectively. In the event | ||
102 | * that only a clockevents device is available, we -ENODEV on the | ||
103 | * clocksource and the jiffies clocksource is used transparently | ||
104 | * instead. No error handling is necessary here. | ||
105 | */ | ||
106 | early_platform_driver_register_all("earlytimer"); | ||
107 | early_platform_driver_probe("earlytimer", 2, 0); | ||
108 | } | ||
109 | |||
94 | void __init time_init(void) | 110 | void __init time_init(void) |
95 | { | 111 | { |
96 | if (board_time_init) | 112 | if (board_time_init) |
97 | board_time_init(); | 113 | board_time_init(); |
98 | 114 | ||
115 | hwblk_init(); | ||
99 | clk_init(); | 116 | clk_init(); |
100 | 117 | ||
101 | rtc_sh_get_time(&xtime); | 118 | rtc_sh_get_time(&xtime); |
@@ -106,15 +123,5 @@ void __init time_init(void) | |||
106 | local_timer_setup(smp_processor_id()); | 123 | local_timer_setup(smp_processor_id()); |
107 | #endif | 124 | #endif |
108 | 125 | ||
109 | /* | 126 | late_time_init = sh_late_time_init; |
110 | * Make sure all compiled-in early timers register themselves. | ||
111 | * | ||
112 | * Run probe() for two "earlytimer" devices, these will be the | ||
113 | * clockevents and clocksource devices respectively. In the event | ||
114 | * that only a clockevents device is available, we -ENODEV on the | ||
115 | * clocksource and the jiffies clocksource is used transparently | ||
116 | * instead. No error handling is necessary here. | ||
117 | */ | ||
118 | early_platform_driver_register_all("earlytimer"); | ||
119 | early_platform_driver_probe("earlytimer", 2, 0); | ||
120 | } | 127 | } |
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 2b772776fcda..563426487c6b 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c | |||
@@ -858,30 +858,6 @@ void __init trap_init(void) | |||
858 | per_cpu_trap_init(); | 858 | per_cpu_trap_init(); |
859 | } | 859 | } |
860 | 860 | ||
861 | void show_trace(struct task_struct *tsk, unsigned long *sp, | ||
862 | struct pt_regs *regs) | ||
863 | { | ||
864 | unsigned long addr; | ||
865 | |||
866 | if (regs && user_mode(regs)) | ||
867 | return; | ||
868 | |||
869 | printk("\nCall trace:\n"); | ||
870 | |||
871 | while (!kstack_end(sp)) { | ||
872 | addr = *sp++; | ||
873 | if (kernel_text_address(addr)) | ||
874 | print_ip_sym(addr); | ||
875 | } | ||
876 | |||
877 | printk("\n"); | ||
878 | |||
879 | if (!tsk) | ||
880 | tsk = current; | ||
881 | |||
882 | debug_show_held_locks(tsk); | ||
883 | } | ||
884 | |||
885 | void show_stack(struct task_struct *tsk, unsigned long *sp) | 861 | void show_stack(struct task_struct *tsk, unsigned long *sp) |
886 | { | 862 | { |
887 | unsigned long stack; | 863 | unsigned long stack; |
diff --git a/arch/sh/kernel/unwinder.c b/arch/sh/kernel/unwinder.c new file mode 100644 index 000000000000..2b30fa28b440 --- /dev/null +++ b/arch/sh/kernel/unwinder.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Matt Fleming | ||
3 | * | ||
4 | * Based, in part, on kernel/time/clocksource.c. | ||
5 | * | ||
6 | * This file provides arbitration code for stack unwinders. | ||
7 | * | ||
8 | * Multiple stack unwinders can be available on a system, usually with | ||
9 | * the most accurate unwinder being the currently active one. | ||
10 | */ | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/list.h> | ||
13 | #include <linux/spinlock.h> | ||
14 | #include <asm/unwinder.h> | ||
15 | #include <asm/atomic.h> | ||
16 | |||
17 | /* | ||
18 | * This is the most basic stack unwinder an architecture can | ||
19 | * provide. For architectures without reliable frame pointers, e.g. | ||
20 | * RISC CPUs, it can be implemented by looking through the stack for | ||
21 | * addresses that lie within the kernel text section. | ||
22 | * | ||
23 | * Other CPUs, e.g. x86, can use their frame pointer register to | ||
24 | * construct more accurate stack traces. | ||
25 | */ | ||
26 | static struct list_head unwinder_list; | ||
27 | static struct unwinder stack_reader = { | ||
28 | .name = "stack-reader", | ||
29 | .dump = stack_reader_dump, | ||
30 | .rating = 50, | ||
31 | .list = { | ||
32 | .next = &unwinder_list, | ||
33 | .prev = &unwinder_list, | ||
34 | }, | ||
35 | }; | ||
36 | |||
37 | /* | ||
38 | * "curr_unwinder" points to the stack unwinder currently in use. This | ||
39 | * is the unwinder with the highest rating. | ||
40 | * | ||
41 | * "unwinder_list" is a linked-list of all available unwinders, sorted | ||
42 | * by rating. | ||
43 | * | ||
44 | * All modifications of "curr_unwinder" and "unwinder_list" must be | ||
45 | * performed whilst holding "unwinder_lock". | ||
46 | */ | ||
47 | static struct unwinder *curr_unwinder = &stack_reader; | ||
48 | |||
49 | static struct list_head unwinder_list = { | ||
50 | .next = &stack_reader.list, | ||
51 | .prev = &stack_reader.list, | ||
52 | }; | ||
53 | |||
54 | static DEFINE_SPINLOCK(unwinder_lock); | ||
55 | |||
56 | static atomic_t unwinder_running = ATOMIC_INIT(0); | ||
57 | |||
58 | /** | ||
59 | * select_unwinder - Select the best registered stack unwinder. | ||
60 | * | ||
61 | * Private function. Must hold unwinder_lock when called. | ||
62 | * | ||
63 | * Select the stack unwinder with the best rating. This is useful for | ||
64 | * setting up curr_unwinder. | ||
65 | */ | ||
66 | static struct unwinder *select_unwinder(void) | ||
67 | { | ||
68 | struct unwinder *best; | ||
69 | |||
70 | if (list_empty(&unwinder_list)) | ||
71 | return NULL; | ||
72 | |||
73 | best = list_entry(unwinder_list.next, struct unwinder, list); | ||
74 | if (best == curr_unwinder) | ||
75 | return NULL; | ||
76 | |||
77 | return best; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * Enqueue the stack unwinder sorted by rating. | ||
82 | */ | ||
83 | static int unwinder_enqueue(struct unwinder *ops) | ||
84 | { | ||
85 | struct list_head *tmp, *entry = &unwinder_list; | ||
86 | |||
87 | list_for_each(tmp, &unwinder_list) { | ||
88 | struct unwinder *o; | ||
89 | |||
90 | o = list_entry(tmp, struct unwinder, list); | ||
91 | if (o == ops) | ||
92 | return -EBUSY; | ||
93 | /* Keep track of the place, where to insert */ | ||
94 | if (o->rating >= ops->rating) | ||
95 | entry = tmp; | ||
96 | } | ||
97 | list_add(&ops->list, entry); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * unwinder_register - Used to install new stack unwinder | ||
104 | * @u: unwinder to be registered | ||
105 | * | ||
106 | * Install the new stack unwinder on the unwinder list, which is sorted | ||
107 | * by rating. | ||
108 | * | ||
109 | * Returns -EBUSY if registration fails, zero otherwise. | ||
110 | */ | ||
111 | int unwinder_register(struct unwinder *u) | ||
112 | { | ||
113 | unsigned long flags; | ||
114 | int ret; | ||
115 | |||
116 | spin_lock_irqsave(&unwinder_lock, flags); | ||
117 | ret = unwinder_enqueue(u); | ||
118 | if (!ret) | ||
119 | curr_unwinder = select_unwinder(); | ||
120 | spin_unlock_irqrestore(&unwinder_lock, flags); | ||
121 | |||
122 | return ret; | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * Unwind the call stack and pass information to the stacktrace_ops | ||
127 | * functions. Also handle the case where we need to switch to a new | ||
128 | * stack dumper because the current one faulted unexpectedly. | ||
129 | */ | ||
130 | void unwind_stack(struct task_struct *task, struct pt_regs *regs, | ||
131 | unsigned long *sp, const struct stacktrace_ops *ops, | ||
132 | void *data) | ||
133 | { | ||
134 | unsigned long flags; | ||
135 | |||
136 | /* | ||
137 | * The problem with unwinders with high ratings is that they are | ||
138 | * inherently more complicated than the simple ones with lower | ||
139 | * ratings. We are therefore more likely to fault in the | ||
140 | * complicated ones, e.g. hitting BUG()s. If we fault in the | ||
141 | * code for the current stack unwinder we try to downgrade to | ||
142 | * one with a lower rating. | ||
143 | * | ||
144 | * Hopefully this will give us a semi-reliable stacktrace so we | ||
145 | * can diagnose why curr_unwinder->dump() faulted. | ||
146 | */ | ||
147 | if (atomic_inc_return(&unwinder_running) != 1) { | ||
148 | spin_lock_irqsave(&unwinder_lock, flags); | ||
149 | |||
150 | if (!list_is_singular(&unwinder_list)) { | ||
151 | list_del(&curr_unwinder->list); | ||
152 | curr_unwinder = select_unwinder(); | ||
153 | } | ||
154 | |||
155 | spin_unlock_irqrestore(&unwinder_lock, flags); | ||
156 | atomic_dec(&unwinder_running); | ||
157 | } | ||
158 | |||
159 | curr_unwinder->dump(task, regs, sp, ops, data); | ||
160 | |||
161 | atomic_dec(&unwinder_running); | ||
162 | } | ||
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S index f53c76acaede..1b7d9d541e01 100644 --- a/arch/sh/kernel/vmlinux.lds.S +++ b/arch/sh/kernel/vmlinux.lds.S | |||
@@ -12,7 +12,7 @@ OUTPUT_ARCH(sh) | |||
12 | 12 | ||
13 | #include <asm/thread_info.h> | 13 | #include <asm/thread_info.h> |
14 | #include <asm/cache.h> | 14 | #include <asm/cache.h> |
15 | #include <asm-generic/vmlinux.lds.h> | 15 | #include <asm/vmlinux.lds.h> |
16 | 16 | ||
17 | ENTRY(_start) | 17 | ENTRY(_start) |
18 | SECTIONS | 18 | SECTIONS |
@@ -50,12 +50,7 @@ SECTIONS | |||
50 | _etext = .; /* End of text section */ | 50 | _etext = .; /* End of text section */ |
51 | } = 0x0009 | 51 | } = 0x0009 |
52 | 52 | ||
53 | . = ALIGN(16); /* Exception table */ | 53 | EXCEPTION_TABLE(16) |
54 | __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { | ||
55 | __start___ex_table = .; | ||
56 | *(__ex_table) | ||
57 | __stop___ex_table = .; | ||
58 | } | ||
59 | 54 | ||
60 | NOTES | 55 | NOTES |
61 | RO_DATA(PAGE_SIZE) | 56 | RO_DATA(PAGE_SIZE) |
@@ -71,69 +66,16 @@ SECTIONS | |||
71 | __uncached_end = .; | 66 | __uncached_end = .; |
72 | } | 67 | } |
73 | 68 | ||
74 | . = ALIGN(THREAD_SIZE); | 69 | RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) |
75 | .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ | ||
76 | *(.data.init_task) | ||
77 | |||
78 | . = ALIGN(L1_CACHE_BYTES); | ||
79 | *(.data.cacheline_aligned) | ||
80 | |||
81 | . = ALIGN(L1_CACHE_BYTES); | ||
82 | *(.data.read_mostly) | ||
83 | |||
84 | . = ALIGN(PAGE_SIZE); | ||
85 | *(.data.page_aligned) | ||
86 | |||
87 | __nosave_begin = .; | ||
88 | *(.data.nosave) | ||
89 | . = ALIGN(PAGE_SIZE); | ||
90 | __nosave_end = .; | ||
91 | |||
92 | DATA_DATA | ||
93 | CONSTRUCTORS | ||
94 | } | ||
95 | 70 | ||
96 | _edata = .; /* End of data section */ | 71 | _edata = .; /* End of data section */ |
97 | 72 | ||
98 | . = ALIGN(PAGE_SIZE); /* Init code and data */ | 73 | DWARF_EH_FRAME |
99 | .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { | ||
100 | __init_begin = .; | ||
101 | _sinittext = .; | ||
102 | INIT_TEXT | ||
103 | _einittext = .; | ||
104 | } | ||
105 | |||
106 | .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { INIT_DATA } | ||
107 | |||
108 | . = ALIGN(16); | ||
109 | .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { | ||
110 | __setup_start = .; | ||
111 | *(.init.setup) | ||
112 | __setup_end = .; | ||
113 | } | ||
114 | |||
115 | .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { | ||
116 | __initcall_start = .; | ||
117 | INITCALLS | ||
118 | __initcall_end = .; | ||
119 | } | ||
120 | |||
121 | .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) { | ||
122 | __con_initcall_start = .; | ||
123 | *(.con_initcall.init) | ||
124 | __con_initcall_end = .; | ||
125 | } | ||
126 | |||
127 | SECURITY_INIT | ||
128 | 74 | ||
129 | #ifdef CONFIG_BLK_DEV_INITRD | 75 | . = ALIGN(PAGE_SIZE); /* Init code and data */ |
130 | . = ALIGN(PAGE_SIZE); | 76 | __init_begin = .; |
131 | .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { | 77 | INIT_TEXT_SECTION(PAGE_SIZE) |
132 | __initramfs_start = .; | 78 | INIT_DATA_SECTION(16) |
133 | *(.init.ramfs) | ||
134 | __initramfs_end = .; | ||
135 | } | ||
136 | #endif | ||
137 | 79 | ||
138 | . = ALIGN(4); | 80 | . = ALIGN(4); |
139 | .machvec.init : AT(ADDR(.machvec.init) - LOAD_OFFSET) { | 81 | .machvec.init : AT(ADDR(.machvec.init) - LOAD_OFFSET) { |
@@ -152,16 +94,10 @@ SECTIONS | |||
152 | .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { EXIT_DATA } | 94 | .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { EXIT_DATA } |
153 | 95 | ||
154 | . = ALIGN(PAGE_SIZE); | 96 | . = ALIGN(PAGE_SIZE); |
155 | .bss : AT(ADDR(.bss) - LOAD_OFFSET) { | 97 | __init_end = .; |
156 | __init_end = .; | 98 | BSS_SECTION(0, PAGE_SIZE, 4) |
157 | __bss_start = .; /* BSS */ | 99 | _ebss = .; /* uClinux MTD sucks */ |
158 | *(.bss.page_aligned) | 100 | _end = . ; |
159 | *(.bss) | ||
160 | *(COMMON) | ||
161 | . = ALIGN(4); | ||
162 | _ebss = .; /* uClinux MTD sucks */ | ||
163 | _end = . ; | ||
164 | } | ||
165 | 101 | ||
166 | /* | 102 | /* |
167 | * When something in the kernel is NOT compiled as a module, the | 103 | * When something in the kernel is NOT compiled as a module, the |
@@ -170,7 +106,7 @@ SECTIONS | |||
170 | * it's a module. | 106 | * it's a module. |
171 | */ | 107 | */ |
172 | /DISCARD/ : { | 108 | /DISCARD/ : { |
173 | *(.exitcall.exit) | 109 | EXIT_CALL |
174 | } | 110 | } |
175 | 111 | ||
176 | STABS_DEBUG | 112 | STABS_DEBUG |