diff options
author | Paul Mundt <lethal@linux-sh.org> | 2009-08-15 00:00:02 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-08-15 00:00:02 -0400 |
commit | 4b6b987969b076298485697bfb0d0e35502642a3 (patch) | |
tree | a8f5ebd6a0b9efbe30272012d759669b0c5ddc13 /arch/sh | |
parent | df47cd096c8f54a5242e3a2ffb4525c804567eda (diff) | |
parent | 60e0a4c7adc700f2d2929cdb2d0055e519a3eb3d (diff) |
Merge branch 'master' into sh/hwblk
Diffstat (limited to 'arch/sh')
42 files changed, 2462 insertions, 204 deletions
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug index 763b792b1611..741d20fab2e1 100644 --- a/arch/sh/Kconfig.debug +++ b/arch/sh/Kconfig.debug | |||
@@ -110,6 +110,14 @@ config DUMP_CODE | |||
110 | 110 | ||
111 | Those looking for more verbose debugging output should say Y. | 111 | Those looking for more verbose debugging output should say Y. |
112 | 112 | ||
113 | config DWARF_UNWINDER | ||
114 | bool "Enable the DWARF unwinder for stacktraces" | ||
115 | select FRAME_POINTER | ||
116 | default n | ||
117 | help | ||
118 | Enabling this option will make stacktraces more accurate, at | ||
119 | the cost of an increase in overall kernel size. | ||
120 | |||
113 | config SH_NO_BSS_INIT | 121 | config SH_NO_BSS_INIT |
114 | bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)" | 122 | bool "Avoid zeroing BSS (to speed-up startup on suitable platforms)" |
115 | depends on DEBUG_KERNEL | 123 | depends on DEBUG_KERNEL |
diff --git a/arch/sh/Makefile b/arch/sh/Makefile index b6ff337fd856..e26421bf9976 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile | |||
@@ -191,6 +191,10 @@ ifeq ($(CONFIG_MCOUNT),y) | |||
191 | KBUILD_CFLAGS += -pg | 191 | KBUILD_CFLAGS += -pg |
192 | endif | 192 | endif |
193 | 193 | ||
194 | ifeq ($(CONFIG_DWARF_UNWINDER),y) | ||
195 | KBUILD_CFLAGS += -fasynchronous-unwind-tables | ||
196 | endif | ||
197 | |||
194 | libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y) | 198 | libs-$(CONFIG_SUPERH32) := arch/sh/lib/ $(libs-y) |
195 | libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y) | 199 | libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y) |
196 | 200 | ||
diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/board-ap325rxa.c index 07a54740d43e..19eea4ab1ccc 100644 --- a/arch/sh/boards/board-ap325rxa.c +++ b/arch/sh/boards/board-ap325rxa.c | |||
@@ -553,7 +553,7 @@ static int __init ap325rxa_devices_setup(void) | |||
553 | return platform_add_devices(ap325rxa_devices, | 553 | return platform_add_devices(ap325rxa_devices, |
554 | ARRAY_SIZE(ap325rxa_devices)); | 554 | ARRAY_SIZE(ap325rxa_devices)); |
555 | } | 555 | } |
556 | device_initcall(ap325rxa_devices_setup); | 556 | arch_initcall(ap325rxa_devices_setup); |
557 | 557 | ||
558 | /* Return the board specific boot mode pin configuration */ | 558 | /* Return the board specific boot mode pin configuration */ |
559 | static int ap325rxa_mode_pins(void) | 559 | static int ap325rxa_mode_pins(void) |
diff --git a/arch/sh/boards/mach-kfr2r09/Makefile b/arch/sh/boards/mach-kfr2r09/Makefile index 77037567633b..5d5867826e3b 100644 --- a/arch/sh/boards/mach-kfr2r09/Makefile +++ b/arch/sh/boards/mach-kfr2r09/Makefile | |||
@@ -1 +1,2 @@ | |||
1 | obj-y := setup.o | 1 | obj-y := setup.o |
2 | obj-$(CONFIG_FB_SH_MOBILE_LCDC) += lcd_wqvga.o | ||
diff --git a/arch/sh/boards/mach-kfr2r09/lcd_wqvga.c b/arch/sh/boards/mach-kfr2r09/lcd_wqvga.c new file mode 100644 index 000000000000..8ccb1cc8b589 --- /dev/null +++ b/arch/sh/boards/mach-kfr2r09/lcd_wqvga.c | |||
@@ -0,0 +1,332 @@ | |||
1 | /* | ||
2 | * KFR2R09 LCD panel support | ||
3 | * | ||
4 | * Copyright (C) 2009 Magnus Damm | ||
5 | * | ||
6 | * Register settings based on the out-of-tree t33fb.c driver | ||
7 | * Copyright (C) 2008 Lineo Solutions, Inc. | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file COPYING in the main directory of this archive for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/delay.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/fb.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include <video/sh_mobile_lcdc.h> | ||
22 | #include <mach/kfr2r09.h> | ||
23 | #include <cpu/sh7724.h> | ||
24 | |||
25 | /* The on-board LCD module is a Hitachi TX07D34VM0AAA. This module is made | ||
26 | * up of a 240x400 LCD hooked up to a R61517 driver IC. The driver IC is | ||
27 | * communicating with the main port of the LCDC using an 18-bit SYS interface. | ||
28 | * | ||
29 | * The device code for this LCD module is 0x01221517. | ||
30 | */ | ||
31 | |||
32 | static const unsigned char data_frame_if[] = { | ||
33 | 0x02, /* WEMODE: 1=cont, 0=one-shot */ | ||
34 | 0x00, 0x00, | ||
35 | 0x00, /* EPF, DFM */ | ||
36 | 0x02, /* RIM[1] : 1 (18bpp) */ | ||
37 | }; | ||
38 | |||
39 | static const unsigned char data_panel[] = { | ||
40 | 0x0b, | ||
41 | 0x63, /* 400 lines */ | ||
42 | 0x04, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00, | ||
43 | }; | ||
44 | |||
45 | static const unsigned char data_timing[] = { | ||
46 | 0x00, 0x00, 0x13, 0x08, 0x08, | ||
47 | }; | ||
48 | |||
49 | static const unsigned char data_timing_src[] = { | ||
50 | 0x11, 0x01, 0x00, 0x01, | ||
51 | }; | ||
52 | |||
53 | static const unsigned char data_gamma[] = { | ||
54 | 0x01, 0x02, 0x08, 0x23, 0x03, 0x0c, 0x00, 0x06, 0x00, 0x00, | ||
55 | 0x01, 0x00, 0x0c, 0x23, 0x03, 0x08, 0x02, 0x06, 0x00, 0x00, | ||
56 | }; | ||
57 | |||
58 | static const unsigned char data_power[] = { | ||
59 | 0x07, 0xc5, 0xdc, 0x02, 0x33, 0x0a, | ||
60 | }; | ||
61 | |||
62 | static unsigned long read_reg(void *sohandle, | ||
63 | struct sh_mobile_lcdc_sys_bus_ops *so) | ||
64 | { | ||
65 | return so->read_data(sohandle); | ||
66 | } | ||
67 | |||
68 | static void write_reg(void *sohandle, | ||
69 | struct sh_mobile_lcdc_sys_bus_ops *so, | ||
70 | int i, unsigned long v) | ||
71 | { | ||
72 | if (i) | ||
73 | so->write_data(sohandle, v); /* PTH4/LCDRS High [param, 17:0] */ | ||
74 | else | ||
75 | so->write_index(sohandle, v); /* PTH4/LCDRS Low [cmd, 7:0] */ | ||
76 | } | ||
77 | |||
78 | static void write_data(void *sohandle, | ||
79 | struct sh_mobile_lcdc_sys_bus_ops *so, | ||
80 | unsigned char const *data, int no_data) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | for (i = 0; i < no_data; i++) | ||
85 | write_reg(sohandle, so, 1, data[i]); | ||
86 | } | ||
87 | |||
88 | static unsigned long read_device_code(void *sohandle, | ||
89 | struct sh_mobile_lcdc_sys_bus_ops *so) | ||
90 | { | ||
91 | unsigned long device_code; | ||
92 | |||
93 | /* access protect OFF */ | ||
94 | write_reg(sohandle, so, 0, 0xb0); | ||
95 | write_reg(sohandle, so, 1, 0x00); | ||
96 | |||
97 | /* deep standby OFF */ | ||
98 | write_reg(sohandle, so, 0, 0xb1); | ||
99 | write_reg(sohandle, so, 1, 0x00); | ||
100 | |||
101 | /* device code command */ | ||
102 | write_reg(sohandle, so, 0, 0xbf); | ||
103 | mdelay(50); | ||
104 | |||
105 | /* dummy read */ | ||
106 | read_reg(sohandle, so); | ||
107 | |||
108 | /* read device code */ | ||
109 | device_code = ((read_reg(sohandle, so) & 0xff) << 24); | ||
110 | device_code |= ((read_reg(sohandle, so) & 0xff) << 16); | ||
111 | device_code |= ((read_reg(sohandle, so) & 0xff) << 8); | ||
112 | device_code |= (read_reg(sohandle, so) & 0xff); | ||
113 | |||
114 | return device_code; | ||
115 | } | ||
116 | |||
117 | static void write_memory_start(void *sohandle, | ||
118 | struct sh_mobile_lcdc_sys_bus_ops *so) | ||
119 | { | ||
120 | write_reg(sohandle, so, 0, 0x2c); | ||
121 | } | ||
122 | |||
123 | static void clear_memory(void *sohandle, | ||
124 | struct sh_mobile_lcdc_sys_bus_ops *so) | ||
125 | { | ||
126 | int i; | ||
127 | |||
128 | /* write start */ | ||
129 | write_memory_start(sohandle, so); | ||
130 | |||
131 | /* paint it black */ | ||
132 | for (i = 0; i < (240 * 400); i++) | ||
133 | write_reg(sohandle, so, 1, 0x00); | ||
134 | } | ||
135 | |||
136 | static void display_on(void *sohandle, | ||
137 | struct sh_mobile_lcdc_sys_bus_ops *so) | ||
138 | { | ||
139 | /* access protect off */ | ||
140 | write_reg(sohandle, so, 0, 0xb0); | ||
141 | write_reg(sohandle, so, 1, 0x00); | ||
142 | |||
143 | /* exit deep standby mode */ | ||
144 | write_reg(sohandle, so, 0, 0xb1); | ||
145 | write_reg(sohandle, so, 1, 0x00); | ||
146 | |||
147 | /* frame memory I/F */ | ||
148 | write_reg(sohandle, so, 0, 0xb3); | ||
149 | write_data(sohandle, so, data_frame_if, ARRAY_SIZE(data_frame_if)); | ||
150 | |||
151 | /* display mode and frame memory write mode */ | ||
152 | write_reg(sohandle, so, 0, 0xb4); | ||
153 | write_reg(sohandle, so, 1, 0x00); /* DBI, internal clock */ | ||
154 | |||
155 | /* panel */ | ||
156 | write_reg(sohandle, so, 0, 0xc0); | ||
157 | write_data(sohandle, so, data_panel, ARRAY_SIZE(data_panel)); | ||
158 | |||
159 | /* timing (normal) */ | ||
160 | write_reg(sohandle, so, 0, 0xc1); | ||
161 | write_data(sohandle, so, data_timing, ARRAY_SIZE(data_timing)); | ||
162 | |||
163 | /* timing (partial) */ | ||
164 | write_reg(sohandle, so, 0, 0xc2); | ||
165 | write_data(sohandle, so, data_timing, ARRAY_SIZE(data_timing)); | ||
166 | |||
167 | /* timing (idle) */ | ||
168 | write_reg(sohandle, so, 0, 0xc3); | ||
169 | write_data(sohandle, so, data_timing, ARRAY_SIZE(data_timing)); | ||
170 | |||
171 | /* timing (source/VCOM/gate driving) */ | ||
172 | write_reg(sohandle, so, 0, 0xc4); | ||
173 | write_data(sohandle, so, data_timing_src, ARRAY_SIZE(data_timing_src)); | ||
174 | |||
175 | /* gamma (red) */ | ||
176 | write_reg(sohandle, so, 0, 0xc8); | ||
177 | write_data(sohandle, so, data_gamma, ARRAY_SIZE(data_gamma)); | ||
178 | |||
179 | /* gamma (green) */ | ||
180 | write_reg(sohandle, so, 0, 0xc9); | ||
181 | write_data(sohandle, so, data_gamma, ARRAY_SIZE(data_gamma)); | ||
182 | |||
183 | /* gamma (blue) */ | ||
184 | write_reg(sohandle, so, 0, 0xca); | ||
185 | write_data(sohandle, so, data_gamma, ARRAY_SIZE(data_gamma)); | ||
186 | |||
187 | /* power (common) */ | ||
188 | write_reg(sohandle, so, 0, 0xd0); | ||
189 | write_data(sohandle, so, data_power, ARRAY_SIZE(data_power)); | ||
190 | |||
191 | /* VCOM */ | ||
192 | write_reg(sohandle, so, 0, 0xd1); | ||
193 | write_reg(sohandle, so, 1, 0x00); | ||
194 | write_reg(sohandle, so, 1, 0x0f); | ||
195 | write_reg(sohandle, so, 1, 0x02); | ||
196 | |||
197 | /* power (normal) */ | ||
198 | write_reg(sohandle, so, 0, 0xd2); | ||
199 | write_reg(sohandle, so, 1, 0x63); | ||
200 | write_reg(sohandle, so, 1, 0x24); | ||
201 | |||
202 | /* power (partial) */ | ||
203 | write_reg(sohandle, so, 0, 0xd3); | ||
204 | write_reg(sohandle, so, 1, 0x63); | ||
205 | write_reg(sohandle, so, 1, 0x24); | ||
206 | |||
207 | /* power (idle) */ | ||
208 | write_reg(sohandle, so, 0, 0xd4); | ||
209 | write_reg(sohandle, so, 1, 0x63); | ||
210 | write_reg(sohandle, so, 1, 0x24); | ||
211 | |||
212 | write_reg(sohandle, so, 0, 0xd8); | ||
213 | write_reg(sohandle, so, 1, 0x77); | ||
214 | write_reg(sohandle, so, 1, 0x77); | ||
215 | |||
216 | /* TE signal */ | ||
217 | write_reg(sohandle, so, 0, 0x35); | ||
218 | write_reg(sohandle, so, 1, 0x00); | ||
219 | |||
220 | /* TE signal line */ | ||
221 | write_reg(sohandle, so, 0, 0x44); | ||
222 | write_reg(sohandle, so, 1, 0x00); | ||
223 | write_reg(sohandle, so, 1, 0x00); | ||
224 | |||
225 | /* column address */ | ||
226 | write_reg(sohandle, so, 0, 0x2a); | ||
227 | write_reg(sohandle, so, 1, 0x00); | ||
228 | write_reg(sohandle, so, 1, 0x00); | ||
229 | write_reg(sohandle, so, 1, 0x00); | ||
230 | write_reg(sohandle, so, 1, 0xef); | ||
231 | |||
232 | /* page address */ | ||
233 | write_reg(sohandle, so, 0, 0x2b); | ||
234 | write_reg(sohandle, so, 1, 0x00); | ||
235 | write_reg(sohandle, so, 1, 0x00); | ||
236 | write_reg(sohandle, so, 1, 0x01); | ||
237 | write_reg(sohandle, so, 1, 0x8f); | ||
238 | |||
239 | /* exit sleep mode */ | ||
240 | write_reg(sohandle, so, 0, 0x11); | ||
241 | |||
242 | mdelay(120); | ||
243 | |||
244 | /* clear vram */ | ||
245 | clear_memory(sohandle, so); | ||
246 | |||
247 | /* display ON */ | ||
248 | write_reg(sohandle, so, 0, 0x29); | ||
249 | mdelay(1); | ||
250 | |||
251 | write_memory_start(sohandle, so); | ||
252 | } | ||
253 | |||
254 | int kfr2r09_lcd_setup(void *board_data, void *sohandle, | ||
255 | struct sh_mobile_lcdc_sys_bus_ops *so) | ||
256 | { | ||
257 | /* power on */ | ||
258 | gpio_set_value(GPIO_PTF4, 0); /* PROTECT/ -> L */ | ||
259 | gpio_set_value(GPIO_PTE4, 0); /* LCD_RST/ -> L */ | ||
260 | gpio_set_value(GPIO_PTF4, 1); /* PROTECT/ -> H */ | ||
261 | udelay(1100); | ||
262 | gpio_set_value(GPIO_PTE4, 1); /* LCD_RST/ -> H */ | ||
263 | udelay(10); | ||
264 | gpio_set_value(GPIO_PTF4, 0); /* PROTECT/ -> L */ | ||
265 | mdelay(20); | ||
266 | |||
267 | if (read_device_code(sohandle, so) != 0x01221517) | ||
268 | return -ENODEV; | ||
269 | |||
270 | pr_info("KFR2R09 WQVGA LCD Module detected.\n"); | ||
271 | |||
272 | display_on(sohandle, so); | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | #define CTRL_CKSW 0x10 | ||
277 | #define CTRL_C10 0x20 | ||
278 | #define CTRL_CPSW 0x80 | ||
279 | #define MAIN_MLED4 0x40 | ||
280 | #define MAIN_MSW 0x80 | ||
281 | |||
282 | static int kfr2r09_lcd_backlight(int on) | ||
283 | { | ||
284 | struct i2c_adapter *a; | ||
285 | struct i2c_msg msg; | ||
286 | unsigned char buf[2]; | ||
287 | int ret; | ||
288 | |||
289 | a = i2c_get_adapter(0); | ||
290 | if (!a) | ||
291 | return -ENODEV; | ||
292 | |||
293 | buf[0] = 0x00; | ||
294 | if (on) | ||
295 | buf[1] = CTRL_CPSW | CTRL_C10 | CTRL_CKSW; | ||
296 | else | ||
297 | buf[1] = 0; | ||
298 | |||
299 | msg.addr = 0x75; | ||
300 | msg.buf = buf; | ||
301 | msg.len = 2; | ||
302 | msg.flags = 0; | ||
303 | ret = i2c_transfer(a, &msg, 1); | ||
304 | if (ret != 1) | ||
305 | return -ENODEV; | ||
306 | |||
307 | buf[0] = 0x01; | ||
308 | if (on) | ||
309 | buf[1] = MAIN_MSW | MAIN_MLED4 | 0x0c; | ||
310 | else | ||
311 | buf[1] = 0; | ||
312 | |||
313 | msg.addr = 0x75; | ||
314 | msg.buf = buf; | ||
315 | msg.len = 2; | ||
316 | msg.flags = 0; | ||
317 | ret = i2c_transfer(a, &msg, 1); | ||
318 | if (ret != 1) | ||
319 | return -ENODEV; | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | void kfr2r09_lcd_on(void *board_data) | ||
325 | { | ||
326 | kfr2r09_lcd_backlight(1); | ||
327 | } | ||
328 | |||
329 | void kfr2r09_lcd_off(void *board_data) | ||
330 | { | ||
331 | kfr2r09_lcd_backlight(0); | ||
332 | } | ||
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 0e9b39034df3..c96533794c26 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c | |||
@@ -11,15 +11,18 @@ | |||
11 | #include <linux/platform_device.h> | 11 | #include <linux/platform_device.h> |
12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/mtd/physmap.h> | 13 | #include <linux/mtd/physmap.h> |
14 | #include <linux/mtd/onenand.h> | ||
14 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
15 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
16 | #include <linux/gpio.h> | 17 | #include <linux/gpio.h> |
17 | #include <linux/input.h> | 18 | #include <linux/input.h> |
19 | #include <video/sh_mobile_lcdc.h> | ||
18 | #include <asm/clock.h> | 20 | #include <asm/clock.h> |
19 | #include <asm/machvec.h> | 21 | #include <asm/machvec.h> |
20 | #include <asm/io.h> | 22 | #include <asm/io.h> |
21 | #include <asm/sh_keysc.h> | 23 | #include <asm/sh_keysc.h> |
22 | #include <cpu/sh7724.h> | 24 | #include <cpu/sh7724.h> |
25 | #include <mach/kfr2r09.h> | ||
23 | 26 | ||
24 | static struct mtd_partition kfr2r09_nor_flash_partitions[] = | 27 | static struct mtd_partition kfr2r09_nor_flash_partitions[] = |
25 | { | 28 | { |
@@ -60,6 +63,21 @@ static struct platform_device kfr2r09_nor_flash_device = { | |||
60 | }, | 63 | }, |
61 | }; | 64 | }; |
62 | 65 | ||
66 | static struct resource kfr2r09_nand_flash_resources[] = { | ||
67 | [0] = { | ||
68 | .name = "NAND Flash", | ||
69 | .start = 0x10000000, | ||
70 | .end = 0x1001ffff, | ||
71 | .flags = IORESOURCE_MEM, | ||
72 | } | ||
73 | }; | ||
74 | |||
75 | static struct platform_device kfr2r09_nand_flash_device = { | ||
76 | .name = "onenand-flash", | ||
77 | .resource = kfr2r09_nand_flash_resources, | ||
78 | .num_resources = ARRAY_SIZE(kfr2r09_nand_flash_resources), | ||
79 | }; | ||
80 | |||
63 | static struct sh_keysc_info kfr2r09_sh_keysc_info = { | 81 | static struct sh_keysc_info kfr2r09_sh_keysc_info = { |
64 | .mode = SH_KEYSC_MODE_1, /* KEYOUT0->4, KEYIN0->4 */ | 82 | .mode = SH_KEYSC_MODE_1, /* KEYOUT0->4, KEYIN0->4 */ |
65 | .scan_timing = 3, | 83 | .scan_timing = 3, |
@@ -100,13 +118,77 @@ static struct platform_device kfr2r09_sh_keysc_device = { | |||
100 | }, | 118 | }, |
101 | }; | 119 | }; |
102 | 120 | ||
121 | static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { | ||
122 | .clock_source = LCDC_CLK_BUS, | ||
123 | .ch[0] = { | ||
124 | .chan = LCDC_CHAN_MAINLCD, | ||
125 | .bpp = 16, | ||
126 | .interface_type = SYS18, | ||
127 | .clock_divider = 6, | ||
128 | .flags = LCDC_FLAGS_DWPOL, | ||
129 | .lcd_cfg = { | ||
130 | .name = "TX07D34VM0AAA", | ||
131 | .xres = 240, | ||
132 | .yres = 400, | ||
133 | .left_margin = 0, | ||
134 | .right_margin = 16, | ||
135 | .hsync_len = 8, | ||
136 | .upper_margin = 0, | ||
137 | .lower_margin = 1, | ||
138 | .vsync_len = 1, | ||
139 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
140 | }, | ||
141 | .lcd_size_cfg = { | ||
142 | .width = 35, | ||
143 | .height = 58, | ||
144 | }, | ||
145 | .board_cfg = { | ||
146 | .setup_sys = kfr2r09_lcd_setup, | ||
147 | .display_on = kfr2r09_lcd_on, | ||
148 | .display_off = kfr2r09_lcd_off, | ||
149 | }, | ||
150 | .sys_bus_cfg = { | ||
151 | .ldmt2r = 0x07010904, | ||
152 | .ldmt3r = 0x14012914, | ||
153 | /* set 1s delay to encourage fsync() */ | ||
154 | .deferred_io_msec = 1000, | ||
155 | }, | ||
156 | } | ||
157 | }; | ||
158 | |||
159 | static struct resource kfr2r09_sh_lcdc_resources[] = { | ||
160 | [0] = { | ||
161 | .name = "LCDC", | ||
162 | .start = 0xfe940000, /* P4-only space */ | ||
163 | .end = 0xfe941fff, | ||
164 | .flags = IORESOURCE_MEM, | ||
165 | }, | ||
166 | [1] = { | ||
167 | .start = 106, | ||
168 | .flags = IORESOURCE_IRQ, | ||
169 | }, | ||
170 | }; | ||
171 | |||
172 | static struct platform_device kfr2r09_sh_lcdc_device = { | ||
173 | .name = "sh_mobile_lcdc_fb", | ||
174 | .num_resources = ARRAY_SIZE(kfr2r09_sh_lcdc_resources), | ||
175 | .resource = kfr2r09_sh_lcdc_resources, | ||
176 | .dev = { | ||
177 | .platform_data = &kfr2r09_sh_lcdc_info, | ||
178 | }, | ||
179 | }; | ||
180 | |||
103 | static struct platform_device *kfr2r09_devices[] __initdata = { | 181 | static struct platform_device *kfr2r09_devices[] __initdata = { |
104 | &kfr2r09_nor_flash_device, | 182 | &kfr2r09_nor_flash_device, |
183 | &kfr2r09_nand_flash_device, | ||
105 | &kfr2r09_sh_keysc_device, | 184 | &kfr2r09_sh_keysc_device, |
185 | &kfr2r09_sh_lcdc_device, | ||
106 | }; | 186 | }; |
107 | 187 | ||
108 | #define BSC_CS0BCR 0xfec10004 | 188 | #define BSC_CS0BCR 0xfec10004 |
109 | #define BSC_CS0WCR 0xfec10024 | 189 | #define BSC_CS0WCR 0xfec10024 |
190 | #define BSC_CS4BCR 0xfec10010 | ||
191 | #define BSC_CS4WCR 0xfec10030 | ||
110 | 192 | ||
111 | static int __init kfr2r09_devices_setup(void) | 193 | static int __init kfr2r09_devices_setup(void) |
112 | { | 194 | { |
@@ -118,6 +200,10 @@ static int __init kfr2r09_devices_setup(void) | |||
118 | ctrl_outl(0x36db0400, BSC_CS0BCR); | 200 | ctrl_outl(0x36db0400, BSC_CS0BCR); |
119 | ctrl_outl(0x00000500, BSC_CS0WCR); | 201 | ctrl_outl(0x00000500, BSC_CS0WCR); |
120 | 202 | ||
203 | /* setup NAND flash at CS4 */ | ||
204 | ctrl_outl(0x36db0400, BSC_CS4BCR); | ||
205 | ctrl_outl(0x00000500, BSC_CS4WCR); | ||
206 | |||
121 | /* setup KEYSC pins */ | 207 | /* setup KEYSC pins */ |
122 | gpio_request(GPIO_FN_KEYOUT0, NULL); | 208 | gpio_request(GPIO_FN_KEYOUT0, NULL); |
123 | gpio_request(GPIO_FN_KEYOUT1, NULL); | 209 | gpio_request(GPIO_FN_KEYOUT1, NULL); |
@@ -131,6 +217,37 @@ static int __init kfr2r09_devices_setup(void) | |||
131 | gpio_request(GPIO_FN_KEYIN4, NULL); | 217 | gpio_request(GPIO_FN_KEYIN4, NULL); |
132 | gpio_request(GPIO_FN_KEYOUT5_IN5, NULL); | 218 | gpio_request(GPIO_FN_KEYOUT5_IN5, NULL); |
133 | 219 | ||
220 | /* setup LCDC pins for SYS panel */ | ||
221 | gpio_request(GPIO_FN_LCDD17, NULL); | ||
222 | gpio_request(GPIO_FN_LCDD16, NULL); | ||
223 | gpio_request(GPIO_FN_LCDD15, NULL); | ||
224 | gpio_request(GPIO_FN_LCDD14, NULL); | ||
225 | gpio_request(GPIO_FN_LCDD13, NULL); | ||
226 | gpio_request(GPIO_FN_LCDD12, NULL); | ||
227 | gpio_request(GPIO_FN_LCDD11, NULL); | ||
228 | gpio_request(GPIO_FN_LCDD10, NULL); | ||
229 | gpio_request(GPIO_FN_LCDD9, NULL); | ||
230 | gpio_request(GPIO_FN_LCDD8, NULL); | ||
231 | gpio_request(GPIO_FN_LCDD7, NULL); | ||
232 | gpio_request(GPIO_FN_LCDD6, NULL); | ||
233 | gpio_request(GPIO_FN_LCDD5, NULL); | ||
234 | gpio_request(GPIO_FN_LCDD4, NULL); | ||
235 | gpio_request(GPIO_FN_LCDD3, NULL); | ||
236 | gpio_request(GPIO_FN_LCDD2, NULL); | ||
237 | gpio_request(GPIO_FN_LCDD1, NULL); | ||
238 | gpio_request(GPIO_FN_LCDD0, NULL); | ||
239 | gpio_request(GPIO_FN_LCDRS, NULL); /* LCD_RS */ | ||
240 | gpio_request(GPIO_FN_LCDCS, NULL); /* LCD_CS/ */ | ||
241 | gpio_request(GPIO_FN_LCDRD, NULL); /* LCD_RD/ */ | ||
242 | gpio_request(GPIO_FN_LCDWR, NULL); /* LCD_WR/ */ | ||
243 | gpio_request(GPIO_FN_LCDVSYN, NULL); /* LCD_VSYNC */ | ||
244 | gpio_request(GPIO_PTE4, NULL); /* LCD_RST/ */ | ||
245 | gpio_direction_output(GPIO_PTE4, 1); | ||
246 | gpio_request(GPIO_PTF4, NULL); /* PROTECT/ */ | ||
247 | gpio_direction_output(GPIO_PTF4, 1); | ||
248 | gpio_request(GPIO_PTU0, NULL); /* LEDSTDBY/ */ | ||
249 | gpio_direction_output(GPIO_PTU0, 1); | ||
250 | |||
134 | return platform_add_devices(kfr2r09_devices, | 251 | return platform_add_devices(kfr2r09_devices, |
135 | ARRAY_SIZE(kfr2r09_devices)); | 252 | ARRAY_SIZE(kfr2r09_devices)); |
136 | } | 253 | } |
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index a508a0fa7315..be8f0d94f6f1 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c | |||
@@ -617,7 +617,7 @@ static int __init migor_devices_setup(void) | |||
617 | 617 | ||
618 | return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices)); | 618 | return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices)); |
619 | } | 619 | } |
620 | __initcall(migor_devices_setup); | 620 | arch_initcall(migor_devices_setup); |
621 | 621 | ||
622 | /* Return the board specific boot mode pin configuration */ | 622 | /* Return the board specific boot mode pin configuration */ |
623 | static int migor_mode_pins(void) | 623 | static int migor_mode_pins(void) |
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 8de5ebc36b67..d922e1b71410 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c | |||
@@ -39,7 +39,15 @@ | |||
39 | * SW41 : abxx xxxx -> a = 0 : Analog monitor | 39 | * SW41 : abxx xxxx -> a = 0 : Analog monitor |
40 | * 1 : Digital monitor | 40 | * 1 : Digital monitor |
41 | * b = 0 : VGA | 41 | * b = 0 : VGA |
42 | * 1 : SVGA | 42 | * 1 : 720p |
43 | */ | ||
44 | |||
45 | /* | ||
46 | * about 720p | ||
47 | * | ||
48 | * When you use 1280 x 720 lcdc output, | ||
49 | * you should change OSC6 lcdc clock from 25.175MHz to 74.25MHz, | ||
50 | * and change SW41 to use 720p | ||
43 | */ | 51 | */ |
44 | 52 | ||
45 | /* Heartbeat */ | 53 | /* Heartbeat */ |
@@ -247,7 +255,7 @@ static struct platform_device ceu1_device = { | |||
247 | }, | 255 | }, |
248 | }; | 256 | }; |
249 | 257 | ||
250 | /* KEYSC */ | 258 | /* KEYSC in SoC (Needs SW33-2 set to ON) */ |
251 | static struct sh_keysc_info keysc_info = { | 259 | static struct sh_keysc_info keysc_info = { |
252 | .mode = SH_KEYSC_MODE_1, | 260 | .mode = SH_KEYSC_MODE_1, |
253 | .scan_timing = 10, | 261 | .scan_timing = 10, |
@@ -264,12 +272,13 @@ static struct sh_keysc_info keysc_info = { | |||
264 | 272 | ||
265 | static struct resource keysc_resources[] = { | 273 | static struct resource keysc_resources[] = { |
266 | [0] = { | 274 | [0] = { |
267 | .start = 0x1a204000, | 275 | .name = "KEYSC", |
268 | .end = 0x1a20400f, | 276 | .start = 0x044b0000, |
277 | .end = 0x044b000f, | ||
269 | .flags = IORESOURCE_MEM, | 278 | .flags = IORESOURCE_MEM, |
270 | }, | 279 | }, |
271 | [1] = { | 280 | [1] = { |
272 | .start = IRQ0_KEY, | 281 | .start = 79, |
273 | .flags = IORESOURCE_IRQ, | 282 | .flags = IORESOURCE_IRQ, |
274 | }, | 283 | }, |
275 | }; | 284 | }; |
@@ -439,6 +448,32 @@ static int __init devices_setup(void) | |||
439 | /* turn on USB clocks, use external clock */ | 448 | /* turn on USB clocks, use external clock */ |
440 | ctrl_outw((ctrl_inw(PORT_MSELCRB) & ~0xc000) | 0x8000, PORT_MSELCRB); | 449 | ctrl_outw((ctrl_inw(PORT_MSELCRB) & ~0xc000) | 0x8000, PORT_MSELCRB); |
441 | 450 | ||
451 | #ifdef CONFIG_PM | ||
452 | /* Let LED9 show STATUS2 */ | ||
453 | gpio_request(GPIO_FN_STATUS2, NULL); | ||
454 | |||
455 | /* Lit LED10 show STATUS0 */ | ||
456 | gpio_request(GPIO_FN_STATUS0, NULL); | ||
457 | |||
458 | /* Lit LED11 show PDSTATUS */ | ||
459 | gpio_request(GPIO_FN_PDSTATUS, NULL); | ||
460 | #else | ||
461 | /* Lit LED9 */ | ||
462 | gpio_request(GPIO_PTJ6, NULL); | ||
463 | gpio_direction_output(GPIO_PTJ6, 1); | ||
464 | gpio_export(GPIO_PTJ6, 0); | ||
465 | |||
466 | /* Lit LED10 */ | ||
467 | gpio_request(GPIO_PTJ5, NULL); | ||
468 | gpio_direction_output(GPIO_PTJ5, 1); | ||
469 | gpio_export(GPIO_PTJ5, 0); | ||
470 | |||
471 | /* Lit LED11 */ | ||
472 | gpio_request(GPIO_PTJ7, NULL); | ||
473 | gpio_direction_output(GPIO_PTJ7, 1); | ||
474 | gpio_export(GPIO_PTJ7, 0); | ||
475 | #endif | ||
476 | |||
442 | /* enable USB0 port */ | 477 | /* enable USB0 port */ |
443 | ctrl_outw(0x0600, 0xa40501d4); | 478 | ctrl_outw(0x0600, 0xa40501d4); |
444 | 479 | ||
@@ -564,15 +599,15 @@ static int __init devices_setup(void) | |||
564 | sh_eth_init(); | 599 | sh_eth_init(); |
565 | 600 | ||
566 | if (sw & SW41_B) { | 601 | if (sw & SW41_B) { |
567 | /* SVGA */ | 602 | /* 720p */ |
568 | lcdc_info.ch[0].lcd_cfg.xres = 800; | 603 | lcdc_info.ch[0].lcd_cfg.xres = 1280; |
569 | lcdc_info.ch[0].lcd_cfg.yres = 600; | 604 | lcdc_info.ch[0].lcd_cfg.yres = 720; |
570 | lcdc_info.ch[0].lcd_cfg.left_margin = 142; | 605 | lcdc_info.ch[0].lcd_cfg.left_margin = 220; |
571 | lcdc_info.ch[0].lcd_cfg.right_margin = 52; | 606 | lcdc_info.ch[0].lcd_cfg.right_margin = 110; |
572 | lcdc_info.ch[0].lcd_cfg.hsync_len = 96; | 607 | lcdc_info.ch[0].lcd_cfg.hsync_len = 40; |
573 | lcdc_info.ch[0].lcd_cfg.upper_margin = 24; | 608 | lcdc_info.ch[0].lcd_cfg.upper_margin = 20; |
574 | lcdc_info.ch[0].lcd_cfg.lower_margin = 2; | 609 | lcdc_info.ch[0].lcd_cfg.lower_margin = 5; |
575 | lcdc_info.ch[0].lcd_cfg.vsync_len = 2; | 610 | lcdc_info.ch[0].lcd_cfg.vsync_len = 5; |
576 | } else { | 611 | } else { |
577 | /* VGA */ | 612 | /* VGA */ |
578 | lcdc_info.ch[0].lcd_cfg.xres = 640; | 613 | lcdc_info.ch[0].lcd_cfg.xres = 640; |
diff --git a/arch/sh/boot/romimage/head.S b/arch/sh/boot/romimage/head.S index 97a087bc9c4a..219bc626dd71 100644 --- a/arch/sh/boot/romimage/head.S +++ b/arch/sh/boot/romimage/head.S | |||
@@ -7,4 +7,4 @@ | |||
7 | .text | 7 | .text |
8 | .global romstart | 8 | .global romstart |
9 | romstart: | 9 | romstart: |
10 | #include <romimage.h> | 10 | #include <mach/romimage.h> |
diff --git a/arch/sh/include/asm/dma-sh.h b/arch/sh/include/asm/dma-sh.h index 0c8f8e14622a..68a5f4cb0343 100644 --- a/arch/sh/include/asm/dma-sh.h +++ b/arch/sh/include/asm/dma-sh.h | |||
@@ -16,6 +16,7 @@ | |||
16 | 16 | ||
17 | /* DMAOR contorl: The DMAOR access size is different by CPU.*/ | 17 | /* DMAOR contorl: The DMAOR access size is different by CPU.*/ |
18 | #if defined(CONFIG_CPU_SUBTYPE_SH7723) || \ | 18 | #if defined(CONFIG_CPU_SUBTYPE_SH7723) || \ |
19 | defined(CONFIG_CPU_SUBTYPE_SH7724) || \ | ||
19 | defined(CONFIG_CPU_SUBTYPE_SH7780) || \ | 20 | defined(CONFIG_CPU_SUBTYPE_SH7780) || \ |
20 | defined(CONFIG_CPU_SUBTYPE_SH7785) | 21 | defined(CONFIG_CPU_SUBTYPE_SH7785) |
21 | #define dmaor_read_reg(n) \ | 22 | #define dmaor_read_reg(n) \ |
diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h new file mode 100644 index 000000000000..60b180728d8d --- /dev/null +++ b/arch/sh/include/asm/dwarf.h | |||
@@ -0,0 +1,402 @@ | |||
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 | */ | ||
9 | #ifndef __ASM_SH_DWARF_H | ||
10 | #define __ASM_SH_DWARF_H | ||
11 | |||
12 | #ifdef CONFIG_DWARF_UNWINDER | ||
13 | |||
14 | /* | ||
15 | * DWARF expression operations | ||
16 | */ | ||
17 | #define DW_OP_addr 0x03 | ||
18 | #define DW_OP_deref 0x06 | ||
19 | #define DW_OP_const1u 0x08 | ||
20 | #define DW_OP_const1s 0x09 | ||
21 | #define DW_OP_const2u 0x0a | ||
22 | #define DW_OP_const2s 0x0b | ||
23 | #define DW_OP_const4u 0x0c | ||
24 | #define DW_OP_const4s 0x0d | ||
25 | #define DW_OP_const8u 0x0e | ||
26 | #define DW_OP_const8s 0x0f | ||
27 | #define DW_OP_constu 0x10 | ||
28 | #define DW_OP_consts 0x11 | ||
29 | #define DW_OP_dup 0x12 | ||
30 | #define DW_OP_drop 0x13 | ||
31 | #define DW_OP_over 0x14 | ||
32 | #define DW_OP_pick 0x15 | ||
33 | #define DW_OP_swap 0x16 | ||
34 | #define DW_OP_rot 0x17 | ||
35 | #define DW_OP_xderef 0x18 | ||
36 | #define DW_OP_abs 0x19 | ||
37 | #define DW_OP_and 0x1a | ||
38 | #define DW_OP_div 0x1b | ||
39 | #define DW_OP_minus 0x1c | ||
40 | #define DW_OP_mod 0x1d | ||
41 | #define DW_OP_mul 0x1e | ||
42 | #define DW_OP_neg 0x1f | ||
43 | #define DW_OP_not 0x20 | ||
44 | #define DW_OP_or 0x21 | ||
45 | #define DW_OP_plus 0x22 | ||
46 | #define DW_OP_plus_uconst 0x23 | ||
47 | #define DW_OP_shl 0x24 | ||
48 | #define DW_OP_shr 0x25 | ||
49 | #define DW_OP_shra 0x26 | ||
50 | #define DW_OP_xor 0x27 | ||
51 | #define DW_OP_skip 0x2f | ||
52 | #define DW_OP_bra 0x28 | ||
53 | #define DW_OP_eq 0x29 | ||
54 | #define DW_OP_ge 0x2a | ||
55 | #define DW_OP_gt 0x2b | ||
56 | #define DW_OP_le 0x2c | ||
57 | #define DW_OP_lt 0x2d | ||
58 | #define DW_OP_ne 0x2e | ||
59 | #define DW_OP_lit0 0x30 | ||
60 | #define DW_OP_lit1 0x31 | ||
61 | #define DW_OP_lit2 0x32 | ||
62 | #define DW_OP_lit3 0x33 | ||
63 | #define DW_OP_lit4 0x34 | ||
64 | #define DW_OP_lit5 0x35 | ||
65 | #define DW_OP_lit6 0x36 | ||
66 | #define DW_OP_lit7 0x37 | ||
67 | #define DW_OP_lit8 0x38 | ||
68 | #define DW_OP_lit9 0x39 | ||
69 | #define DW_OP_lit10 0x3a | ||
70 | #define DW_OP_lit11 0x3b | ||
71 | #define DW_OP_lit12 0x3c | ||
72 | #define DW_OP_lit13 0x3d | ||
73 | #define DW_OP_lit14 0x3e | ||
74 | #define DW_OP_lit15 0x3f | ||
75 | #define DW_OP_lit16 0x40 | ||
76 | #define DW_OP_lit17 0x41 | ||
77 | #define DW_OP_lit18 0x42 | ||
78 | #define DW_OP_lit19 0x43 | ||
79 | #define DW_OP_lit20 0x44 | ||
80 | #define DW_OP_lit21 0x45 | ||
81 | #define DW_OP_lit22 0x46 | ||
82 | #define DW_OP_lit23 0x47 | ||
83 | #define DW_OP_lit24 0x48 | ||
84 | #define DW_OP_lit25 0x49 | ||
85 | #define DW_OP_lit26 0x4a | ||
86 | #define DW_OP_lit27 0x4b | ||
87 | #define DW_OP_lit28 0x4c | ||
88 | #define DW_OP_lit29 0x4d | ||
89 | #define DW_OP_lit30 0x4e | ||
90 | #define DW_OP_lit31 0x4f | ||
91 | #define DW_OP_reg0 0x50 | ||
92 | #define DW_OP_reg1 0x51 | ||
93 | #define DW_OP_reg2 0x52 | ||
94 | #define DW_OP_reg3 0x53 | ||
95 | #define DW_OP_reg4 0x54 | ||
96 | #define DW_OP_reg5 0x55 | ||
97 | #define DW_OP_reg6 0x56 | ||
98 | #define DW_OP_reg7 0x57 | ||
99 | #define DW_OP_reg8 0x58 | ||
100 | #define DW_OP_reg9 0x59 | ||
101 | #define DW_OP_reg10 0x5a | ||
102 | #define DW_OP_reg11 0x5b | ||
103 | #define DW_OP_reg12 0x5c | ||
104 | #define DW_OP_reg13 0x5d | ||
105 | #define DW_OP_reg14 0x5e | ||
106 | #define DW_OP_reg15 0x5f | ||
107 | #define DW_OP_reg16 0x60 | ||
108 | #define DW_OP_reg17 0x61 | ||
109 | #define DW_OP_reg18 0x62 | ||
110 | #define DW_OP_reg19 0x63 | ||
111 | #define DW_OP_reg20 0x64 | ||
112 | #define DW_OP_reg21 0x65 | ||
113 | #define DW_OP_reg22 0x66 | ||
114 | #define DW_OP_reg23 0x67 | ||
115 | #define DW_OP_reg24 0x68 | ||
116 | #define DW_OP_reg25 0x69 | ||
117 | #define DW_OP_reg26 0x6a | ||
118 | #define DW_OP_reg27 0x6b | ||
119 | #define DW_OP_reg28 0x6c | ||
120 | #define DW_OP_reg29 0x6d | ||
121 | #define DW_OP_reg30 0x6e | ||
122 | #define DW_OP_reg31 0x6f | ||
123 | #define DW_OP_breg0 0x70 | ||
124 | #define DW_OP_breg1 0x71 | ||
125 | #define DW_OP_breg2 0x72 | ||
126 | #define DW_OP_breg3 0x73 | ||
127 | #define DW_OP_breg4 0x74 | ||
128 | #define DW_OP_breg5 0x75 | ||
129 | #define DW_OP_breg6 0x76 | ||
130 | #define DW_OP_breg7 0x77 | ||
131 | #define DW_OP_breg8 0x78 | ||
132 | #define DW_OP_breg9 0x79 | ||
133 | #define DW_OP_breg10 0x7a | ||
134 | #define DW_OP_breg11 0x7b | ||
135 | #define DW_OP_breg12 0x7c | ||
136 | #define DW_OP_breg13 0x7d | ||
137 | #define DW_OP_breg14 0x7e | ||
138 | #define DW_OP_breg15 0x7f | ||
139 | #define DW_OP_breg16 0x80 | ||
140 | #define DW_OP_breg17 0x81 | ||
141 | #define DW_OP_breg18 0x82 | ||
142 | #define DW_OP_breg19 0x83 | ||
143 | #define DW_OP_breg20 0x84 | ||
144 | #define DW_OP_breg21 0x85 | ||
145 | #define DW_OP_breg22 0x86 | ||
146 | #define DW_OP_breg23 0x87 | ||
147 | #define DW_OP_breg24 0x88 | ||
148 | #define DW_OP_breg25 0x89 | ||
149 | #define DW_OP_breg26 0x8a | ||
150 | #define DW_OP_breg27 0x8b | ||
151 | #define DW_OP_breg28 0x8c | ||
152 | #define DW_OP_breg29 0x8d | ||
153 | #define DW_OP_breg30 0x8e | ||
154 | #define DW_OP_breg31 0x8f | ||
155 | #define DW_OP_regx 0x90 | ||
156 | #define DW_OP_fbreg 0x91 | ||
157 | #define DW_OP_bregx 0x92 | ||
158 | #define DW_OP_piece 0x93 | ||
159 | #define DW_OP_deref_size 0x94 | ||
160 | #define DW_OP_xderef_size 0x95 | ||
161 | #define DW_OP_nop 0x96 | ||
162 | #define DW_OP_push_object_address 0x97 | ||
163 | #define DW_OP_call2 0x98 | ||
164 | #define DW_OP_call4 0x99 | ||
165 | #define DW_OP_call_ref 0x9a | ||
166 | #define DW_OP_form_tls_address 0x9b | ||
167 | #define DW_OP_call_frame_cfa 0x9c | ||
168 | #define DW_OP_bit_piece 0x9d | ||
169 | #define DW_OP_lo_user 0xe0 | ||
170 | #define DW_OP_hi_user 0xff | ||
171 | |||
172 | /* | ||
173 | * Addresses used in FDE entries in the .eh_frame section may be encoded | ||
174 | * using one of the following encodings. | ||
175 | */ | ||
176 | #define DW_EH_PE_absptr 0x00 | ||
177 | #define DW_EH_PE_omit 0xff | ||
178 | #define DW_EH_PE_uleb128 0x01 | ||
179 | #define DW_EH_PE_udata2 0x02 | ||
180 | #define DW_EH_PE_udata4 0x03 | ||
181 | #define DW_EH_PE_udata8 0x04 | ||
182 | #define DW_EH_PE_sleb128 0x09 | ||
183 | #define DW_EH_PE_sdata2 0x0a | ||
184 | #define DW_EH_PE_sdata4 0x0b | ||
185 | #define DW_EH_PE_sdata8 0x0c | ||
186 | #define DW_EH_PE_signed 0x09 | ||
187 | |||
188 | #define DW_EH_PE_pcrel 0x10 | ||
189 | |||
190 | /* | ||
191 | * The architecture-specific register number that contains the return | ||
192 | * address in the .debug_frame table. | ||
193 | */ | ||
194 | #define DWARF_ARCH_RA_REG 17 | ||
195 | |||
196 | #ifndef __ASSEMBLY__ | ||
197 | /* | ||
198 | * Read either the frame pointer (r14) or the stack pointer (r15). | ||
199 | * NOTE: this MUST be inlined. | ||
200 | */ | ||
201 | static __always_inline unsigned long dwarf_read_arch_reg(unsigned int reg) | ||
202 | { | ||
203 | unsigned long value; | ||
204 | |||
205 | switch (reg) { | ||
206 | case 14: | ||
207 | __asm__ __volatile__("mov r14, %0\n" : "=r" (value)); | ||
208 | break; | ||
209 | case 15: | ||
210 | __asm__ __volatile__("mov r15, %0\n" : "=r" (value)); | ||
211 | break; | ||
212 | default: | ||
213 | BUG(); | ||
214 | } | ||
215 | |||
216 | return value; | ||
217 | } | ||
218 | |||
219 | /** | ||
220 | * dwarf_cie - Common Information Entry | ||
221 | */ | ||
222 | struct dwarf_cie { | ||
223 | unsigned long length; | ||
224 | unsigned long cie_id; | ||
225 | unsigned char version; | ||
226 | const char *augmentation; | ||
227 | unsigned int code_alignment_factor; | ||
228 | int data_alignment_factor; | ||
229 | |||
230 | /* Which column in the rule table represents return addr of func. */ | ||
231 | unsigned int return_address_reg; | ||
232 | |||
233 | unsigned char *initial_instructions; | ||
234 | unsigned char *instructions_end; | ||
235 | |||
236 | unsigned char encoding; | ||
237 | |||
238 | unsigned long cie_pointer; | ||
239 | |||
240 | struct list_head link; | ||
241 | |||
242 | unsigned long flags; | ||
243 | #define DWARF_CIE_Z_AUGMENTATION (1 << 0) | ||
244 | }; | ||
245 | |||
246 | /** | ||
247 | * dwarf_fde - Frame Description Entry | ||
248 | */ | ||
249 | struct dwarf_fde { | ||
250 | unsigned long length; | ||
251 | unsigned long cie_pointer; | ||
252 | struct dwarf_cie *cie; | ||
253 | unsigned long initial_location; | ||
254 | unsigned long address_range; | ||
255 | unsigned char *instructions; | ||
256 | unsigned char *end; | ||
257 | struct list_head link; | ||
258 | }; | ||
259 | |||
260 | /** | ||
261 | * dwarf_frame - DWARF information for a frame in the call stack | ||
262 | */ | ||
263 | struct dwarf_frame { | ||
264 | struct dwarf_frame *prev, *next; | ||
265 | |||
266 | unsigned long pc; | ||
267 | |||
268 | struct dwarf_reg *regs; | ||
269 | unsigned int num_regs; /* how many regs are allocated? */ | ||
270 | |||
271 | unsigned int depth; /* what level are we in the callstack? */ | ||
272 | |||
273 | unsigned long cfa; | ||
274 | |||
275 | /* Valid when DW_FRAME_CFA_REG_OFFSET is set in flags */ | ||
276 | unsigned int cfa_register; | ||
277 | unsigned int cfa_offset; | ||
278 | |||
279 | /* Valid when DW_FRAME_CFA_REG_EXP is set in flags */ | ||
280 | unsigned char *cfa_expr; | ||
281 | unsigned int cfa_expr_len; | ||
282 | |||
283 | unsigned long flags; | ||
284 | #define DWARF_FRAME_CFA_REG_OFFSET (1 << 0) | ||
285 | #define DWARF_FRAME_CFA_REG_EXP (1 << 1) | ||
286 | |||
287 | unsigned long return_addr; | ||
288 | }; | ||
289 | |||
290 | /** | ||
291 | * dwarf_reg - DWARF register | ||
292 | * @flags: Describes how to calculate the value of this register | ||
293 | */ | ||
294 | struct dwarf_reg { | ||
295 | unsigned long addr; | ||
296 | unsigned long flags; | ||
297 | #define DWARF_REG_OFFSET (1 << 0) | ||
298 | }; | ||
299 | |||
300 | /** | ||
301 | * dwarf_stack - a DWARF stack contains a collection of DWARF frames | ||
302 | * @depth: the number of frames in the stack | ||
303 | * @level: an array of DWARF frames, indexed by stack level | ||
304 | * | ||
305 | */ | ||
306 | struct dwarf_stack { | ||
307 | unsigned int depth; | ||
308 | struct dwarf_frame **level; | ||
309 | }; | ||
310 | |||
311 | /* | ||
312 | * Call Frame instruction opcodes. | ||
313 | */ | ||
314 | #define DW_CFA_advance_loc 0x40 | ||
315 | #define DW_CFA_offset 0x80 | ||
316 | #define DW_CFA_restore 0xc0 | ||
317 | #define DW_CFA_nop 0x00 | ||
318 | #define DW_CFA_set_loc 0x01 | ||
319 | #define DW_CFA_advance_loc1 0x02 | ||
320 | #define DW_CFA_advance_loc2 0x03 | ||
321 | #define DW_CFA_advance_loc4 0x04 | ||
322 | #define DW_CFA_offset_extended 0x05 | ||
323 | #define DW_CFA_restore_extended 0x06 | ||
324 | #define DW_CFA_undefined 0x07 | ||
325 | #define DW_CFA_same_value 0x08 | ||
326 | #define DW_CFA_register 0x09 | ||
327 | #define DW_CFA_remember_state 0x0a | ||
328 | #define DW_CFA_restore_state 0x0b | ||
329 | #define DW_CFA_def_cfa 0x0c | ||
330 | #define DW_CFA_def_cfa_register 0x0d | ||
331 | #define DW_CFA_def_cfa_offset 0x0e | ||
332 | #define DW_CFA_def_cfa_expression 0x0f | ||
333 | #define DW_CFA_expression 0x10 | ||
334 | #define DW_CFA_offset_extended_sf 0x11 | ||
335 | #define DW_CFA_def_cfa_sf 0x12 | ||
336 | #define DW_CFA_def_cfa_offset_sf 0x13 | ||
337 | #define DW_CFA_val_offset 0x14 | ||
338 | #define DW_CFA_val_offset_sf 0x15 | ||
339 | #define DW_CFA_val_expression 0x16 | ||
340 | #define DW_CFA_lo_user 0x1c | ||
341 | #define DW_CFA_hi_user 0x3f | ||
342 | |||
343 | /* | ||
344 | * Some call frame instructions encode their operands in the opcode. We | ||
345 | * need some helper functions to extract both the opcode and operands | ||
346 | * from an instruction. | ||
347 | */ | ||
348 | static inline unsigned int DW_CFA_opcode(unsigned long insn) | ||
349 | { | ||
350 | return (insn & 0xc0); | ||
351 | } | ||
352 | |||
353 | static inline unsigned int DW_CFA_operand(unsigned long insn) | ||
354 | { | ||
355 | return (insn & 0x3f); | ||
356 | } | ||
357 | |||
358 | #define DW_EH_FRAME_CIE 0 /* .eh_frame CIE IDs are 0 */ | ||
359 | #define DW_CIE_ID 0xffffffff | ||
360 | #define DW64_CIE_ID 0xffffffffffffffffULL | ||
361 | |||
362 | /* | ||
363 | * DWARF FDE/CIE length field values. | ||
364 | */ | ||
365 | #define DW_EXT_LO 0xfffffff0 | ||
366 | #define DW_EXT_HI 0xffffffff | ||
367 | #define DW_EXT_DWARF64 DW_EXT_HI | ||
368 | |||
369 | extern void dwarf_unwinder_init(void); | ||
370 | |||
371 | extern struct dwarf_frame *dwarf_unwind_stack(unsigned long, | ||
372 | struct dwarf_frame *); | ||
373 | #endif /* __ASSEMBLY__ */ | ||
374 | |||
375 | #define CFI_STARTPROC .cfi_startproc | ||
376 | #define CFI_ENDPROC .cfi_endproc | ||
377 | #define CFI_DEF_CFA .cfi_def_cfa | ||
378 | #define CFI_REGISTER .cfi_register | ||
379 | #define CFI_REL_OFFSET .cfi_rel_offset | ||
380 | |||
381 | #else | ||
382 | |||
383 | /* | ||
384 | * Use the asm comment character to ignore the rest of the line. | ||
385 | */ | ||
386 | #define CFI_IGNORE ! | ||
387 | |||
388 | #define CFI_STARTPROC CFI_IGNORE | ||
389 | #define CFI_ENDPROC CFI_IGNORE | ||
390 | #define CFI_DEF_CFA CFI_IGNORE | ||
391 | #define CFI_REGISTER CFI_IGNORE | ||
392 | #define CFI_REL_OFFSET CFI_IGNORE | ||
393 | |||
394 | #ifndef __ASSEMBLY__ | ||
395 | static inline void dwarf_unwinder_init(void) | ||
396 | { | ||
397 | } | ||
398 | #endif | ||
399 | |||
400 | #endif /* CONFIG_DWARF_UNWINDER */ | ||
401 | |||
402 | #endif /* __ASM_SH_DWARF_H */ | ||
diff --git a/arch/sh/include/asm/entry-macros.S b/arch/sh/include/asm/entry-macros.S index 1bdd93891cd7..64fd0de24daf 100644 --- a/arch/sh/include/asm/entry-macros.S +++ b/arch/sh/include/asm/entry-macros.S | |||
@@ -108,3 +108,15 @@ | |||
108 | #else | 108 | #else |
109 | # define PREF(x) nop | 109 | # define PREF(x) nop |
110 | #endif | 110 | #endif |
111 | |||
112 | /* | ||
113 | * Macro for use within assembly. Because the DWARF unwinder | ||
114 | * needs to use the frame register to unwind the stack, we | ||
115 | * need to setup r14 with the value of the stack pointer as | ||
116 | * the return address is usually on the stack somewhere. | ||
117 | */ | ||
118 | .macro setup_frame_reg | ||
119 | #ifdef CONFIG_DWARF_UNWINDER | ||
120 | mov r15, r14 | ||
121 | #endif | ||
122 | .endm | ||
diff --git a/arch/sh/include/asm/hardirq.h b/arch/sh/include/asm/hardirq.h index 715ee237fc77..a5be4afa790b 100644 --- a/arch/sh/include/asm/hardirq.h +++ b/arch/sh/include/asm/hardirq.h | |||
@@ -1,16 +1,9 @@ | |||
1 | #ifndef __ASM_SH_HARDIRQ_H | 1 | #ifndef __ASM_SH_HARDIRQ_H |
2 | #define __ASM_SH_HARDIRQ_H | 2 | #define __ASM_SH_HARDIRQ_H |
3 | 3 | ||
4 | #include <linux/threads.h> | ||
5 | #include <linux/irq.h> | ||
6 | |||
7 | /* entry.S is sensitive to the offsets of these fields */ | ||
8 | typedef struct { | ||
9 | unsigned int __softirq_pending; | ||
10 | } ____cacheline_aligned irq_cpustat_t; | ||
11 | |||
12 | #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ | ||
13 | |||
14 | extern void ack_bad_irq(unsigned int irq); | 4 | extern void ack_bad_irq(unsigned int irq); |
5 | #define ack_bad_irq ack_bad_irq | ||
6 | |||
7 | #include <asm-generic/hardirq.h> | ||
15 | 8 | ||
16 | #endif /* __ASM_SH_HARDIRQ_H */ | 9 | #endif /* __ASM_SH_HARDIRQ_H */ |
diff --git a/arch/sh/include/asm/sections.h b/arch/sh/include/asm/sections.h index 01a4076a3719..a78701da775b 100644 --- a/arch/sh/include/asm/sections.h +++ b/arch/sh/include/asm/sections.h | |||
@@ -7,6 +7,7 @@ extern void __nosave_begin, __nosave_end; | |||
7 | extern long __machvec_start, __machvec_end; | 7 | extern long __machvec_start, __machvec_end; |
8 | extern char __uncached_start, __uncached_end; | 8 | extern char __uncached_start, __uncached_end; |
9 | extern char _ebss[]; | 9 | extern char _ebss[]; |
10 | extern char __start_eh_frame[], __stop_eh_frame[]; | ||
10 | 11 | ||
11 | #endif /* __ASM_SH_SECTIONS_H */ | 12 | #endif /* __ASM_SH_SECTIONS_H */ |
12 | 13 | ||
diff --git a/arch/sh/include/asm/stacktrace.h b/arch/sh/include/asm/stacktrace.h new file mode 100644 index 000000000000..797018213718 --- /dev/null +++ b/arch/sh/include/asm/stacktrace.h | |||
@@ -0,0 +1,25 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Matt Fleming | ||
3 | * | ||
4 | * Based on: | ||
5 | * The x86 implementation - arch/x86/include/asm/stacktrace.h | ||
6 | */ | ||
7 | #ifndef _ASM_SH_STACKTRACE_H | ||
8 | #define _ASM_SH_STACKTRACE_H | ||
9 | |||
10 | /* Generic stack tracer with callbacks */ | ||
11 | |||
12 | struct stacktrace_ops { | ||
13 | void (*warning)(void *data, char *msg); | ||
14 | /* msg must contain %s for the symbol */ | ||
15 | void (*warning_symbol)(void *data, char *msg, unsigned long symbol); | ||
16 | void (*address)(void *data, unsigned long address, int reliable); | ||
17 | /* On negative return stop dumping */ | ||
18 | int (*stack)(void *data, char *name); | ||
19 | }; | ||
20 | |||
21 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, | ||
22 | unsigned long *stack, | ||
23 | const struct stacktrace_ops *ops, void *data); | ||
24 | |||
25 | #endif /* _ASM_SH_STACKTRACE_H */ | ||
diff --git a/arch/sh/include/asm/unwinder.h b/arch/sh/include/asm/unwinder.h new file mode 100644 index 000000000000..3dc551453e28 --- /dev/null +++ b/arch/sh/include/asm/unwinder.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #ifndef _LINUX_UNWINDER_H | ||
2 | #define _LINUX_UNWINDER_H | ||
3 | |||
4 | #include <asm/stacktrace.h> | ||
5 | |||
6 | struct unwinder { | ||
7 | const char *name; | ||
8 | struct list_head list; | ||
9 | int rating; | ||
10 | void (*dump)(struct task_struct *, struct pt_regs *, | ||
11 | unsigned long *, const struct stacktrace_ops *, void *); | ||
12 | }; | ||
13 | |||
14 | extern int unwinder_init(void); | ||
15 | extern int unwinder_register(struct unwinder *); | ||
16 | |||
17 | extern void unwind_stack(struct task_struct *, struct pt_regs *, | ||
18 | unsigned long *, const struct stacktrace_ops *, | ||
19 | void *); | ||
20 | |||
21 | extern void stack_reader_dump(struct task_struct *, struct pt_regs *, | ||
22 | unsigned long *, const struct stacktrace_ops *, | ||
23 | void *); | ||
24 | |||
25 | #endif /* _LINUX_UNWINDER_H */ | ||
diff --git a/arch/sh/include/asm/vmlinux.lds.h b/arch/sh/include/asm/vmlinux.lds.h new file mode 100644 index 000000000000..244ec4ad9a79 --- /dev/null +++ b/arch/sh/include/asm/vmlinux.lds.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #ifndef __ASM_SH_VMLINUX_LDS_H | ||
2 | #define __ASM_SH_VMLINUX_LDS_H | ||
3 | |||
4 | #include <asm-generic/vmlinux.lds.h> | ||
5 | |||
6 | #ifdef CONFIG_DWARF_UNWINDER | ||
7 | #define DWARF_EH_FRAME \ | ||
8 | .eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) { \ | ||
9 | VMLINUX_SYMBOL(__start_eh_frame) = .; \ | ||
10 | *(.eh_frame) \ | ||
11 | VMLINUX_SYMBOL(__stop_eh_frame) = .; \ | ||
12 | } | ||
13 | #else | ||
14 | #define DWARF_EH_FRAME | ||
15 | #endif | ||
16 | |||
17 | #endif /* __ASM_SH_VMLINUX_LDS_H */ | ||
diff --git a/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h b/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h index 0ed5178fed69..f0886bc880e0 100644 --- a/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h +++ b/arch/sh/include/cpu-sh4/cpu/dma-sh4a.h | |||
@@ -16,7 +16,8 @@ | |||
16 | #define DMAE0_IRQ 38 | 16 | #define DMAE0_IRQ 38 |
17 | #define SH_DMAC_BASE0 0xFF608020 | 17 | #define SH_DMAC_BASE0 0xFF608020 |
18 | #define SH_DMARS_BASE 0xFF609000 | 18 | #define SH_DMARS_BASE 0xFF609000 |
19 | #elif defined(CONFIG_CPU_SUBTYPE_SH7723) | 19 | #elif defined(CONFIG_CPU_SUBTYPE_SH7723) || \ |
20 | defined(CONFIG_CPU_SUBTYPE_SH7724) | ||
20 | #define DMTE0_IRQ 48 /* DMAC0A*/ | 21 | #define DMTE0_IRQ 48 /* DMAC0A*/ |
21 | #define DMTE4_IRQ 40 /* DMAC0B */ | 22 | #define DMTE4_IRQ 40 /* DMAC0B */ |
22 | #define DMTE6_IRQ 42 | 23 | #define DMTE6_IRQ 42 |
diff --git a/arch/sh/include/mach-common/mach/migor.h b/arch/sh/include/mach-common/mach/migor.h deleted file mode 100644 index e451f0229e00..000000000000 --- a/arch/sh/include/mach-common/mach/migor.h +++ /dev/null | |||
@@ -1,64 +0,0 @@ | |||
1 | #ifndef __ASM_SH_MIGOR_H | ||
2 | #define __ASM_SH_MIGOR_H | ||
3 | |||
4 | /* | ||
5 | * linux/include/asm-sh/migor.h | ||
6 | * | ||
7 | * Copyright (C) 2008 Renesas Solutions | ||
8 | * | ||
9 | * Portions Copyright (C) 2007 Nobuhiro Iwamatsu | ||
10 | * | ||
11 | * This file is subject to the terms and conditions of the GNU General Public | ||
12 | * License. See the file "COPYING" in the main directory of this archive | ||
13 | * for more details. | ||
14 | * | ||
15 | */ | ||
16 | #include <asm/addrspace.h> | ||
17 | |||
18 | /* GPIO */ | ||
19 | #define PORT_PACR 0xa4050100 | ||
20 | #define PORT_PDCR 0xa4050106 | ||
21 | #define PORT_PECR 0xa4050108 | ||
22 | #define PORT_PHCR 0xa405010e | ||
23 | #define PORT_PJCR 0xa4050110 | ||
24 | #define PORT_PKCR 0xa4050112 | ||
25 | #define PORT_PLCR 0xa4050114 | ||
26 | #define PORT_PMCR 0xa4050116 | ||
27 | #define PORT_PRCR 0xa405011c | ||
28 | #define PORT_PTCR 0xa4050140 | ||
29 | #define PORT_PUCR 0xa4050142 | ||
30 | #define PORT_PVCR 0xa4050144 | ||
31 | #define PORT_PWCR 0xa4050146 | ||
32 | #define PORT_PXCR 0xa4050148 | ||
33 | #define PORT_PYCR 0xa405014a | ||
34 | #define PORT_PZCR 0xa405014c | ||
35 | #define PORT_PADR 0xa4050120 | ||
36 | #define PORT_PHDR 0xa405012e | ||
37 | #define PORT_PTDR 0xa4050160 | ||
38 | #define PORT_PWDR 0xa4050166 | ||
39 | |||
40 | #define PORT_HIZCRA 0xa4050158 | ||
41 | #define PORT_HIZCRC 0xa405015c | ||
42 | |||
43 | #define PORT_MSELCRB 0xa4050182 | ||
44 | |||
45 | #define PORT_PSELA 0xa405014e | ||
46 | #define PORT_PSELB 0xa4050150 | ||
47 | #define PORT_PSELC 0xa4050152 | ||
48 | #define PORT_PSELD 0xa4050154 | ||
49 | #define PORT_PSELE 0xa4050156 | ||
50 | |||
51 | #define PORT_HIZCRA 0xa4050158 | ||
52 | #define PORT_HIZCRB 0xa405015a | ||
53 | #define PORT_HIZCRC 0xa405015c | ||
54 | |||
55 | #define BSC_CS4BCR 0xfec10010 | ||
56 | #define BSC_CS6ABCR 0xfec1001c | ||
57 | #define BSC_CS4WCR 0xfec10030 | ||
58 | |||
59 | #include <video/sh_mobile_lcdc.h> | ||
60 | |||
61 | int migor_lcd_qvga_setup(void *board_data, void *sys_ops_handle, | ||
62 | struct sh_mobile_lcdc_sys_bus_ops *sys_ops); | ||
63 | |||
64 | #endif /* __ASM_SH_MIGOR_H */ | ||
diff --git a/arch/sh/include/mach-common/romimage.h b/arch/sh/include/mach-common/mach/romimage.h index 267e24112d82..267e24112d82 100644 --- a/arch/sh/include/mach-common/romimage.h +++ b/arch/sh/include/mach-common/mach/romimage.h | |||
diff --git a/arch/sh/include/mach-kfr2r09/mach/kfr2r09.h b/arch/sh/include/mach-kfr2r09/mach/kfr2r09.h new file mode 100644 index 000000000000..174374e19547 --- /dev/null +++ b/arch/sh/include/mach-kfr2r09/mach/kfr2r09.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #ifndef __ASM_SH_KFR2R09_H | ||
2 | #define __ASM_SH_KFR2R09_H | ||
3 | |||
4 | #include <video/sh_mobile_lcdc.h> | ||
5 | |||
6 | #ifdef CONFIG_FB_SH_MOBILE_LCDC | ||
7 | void kfr2r09_lcd_on(void *board_data); | ||
8 | void kfr2r09_lcd_off(void *board_data); | ||
9 | int kfr2r09_lcd_setup(void *board_data, void *sys_ops_handle, | ||
10 | struct sh_mobile_lcdc_sys_bus_ops *sys_ops); | ||
11 | #else | ||
12 | static inline void kfr2r09_lcd_on(void *board_data) {} | ||
13 | static inline void kfr2r09_lcd_off(void *board_data) {} | ||
14 | static inline int kfr2r09_lcd_setup(void *board_data, void *sys_ops_handle, | ||
15 | struct sh_mobile_lcdc_sys_bus_ops *sys_ops) | ||
16 | { | ||
17 | return -ENODEV; | ||
18 | } | ||
19 | #endif | ||
20 | |||
21 | #endif /* __ASM_SH_KFR2R09_H */ | ||
diff --git a/arch/sh/include/mach-kfr2r09/partner-jet-setup.txt b/arch/sh/include/mach-kfr2r09/mach/partner-jet-setup.txt index 9c85088728a7..9c85088728a7 100644 --- a/arch/sh/include/mach-kfr2r09/partner-jet-setup.txt +++ b/arch/sh/include/mach-kfr2r09/mach/partner-jet-setup.txt | |||
diff --git a/arch/sh/include/mach-kfr2r09/romimage.h b/arch/sh/include/mach-kfr2r09/mach/romimage.h index f5aa8e16770c..f5aa8e16770c 100644 --- a/arch/sh/include/mach-kfr2r09/romimage.h +++ b/arch/sh/include/mach-kfr2r09/mach/romimage.h | |||
diff --git a/arch/sh/include/mach-migor/mach/migor.h b/arch/sh/include/mach-migor/mach/migor.h new file mode 100644 index 000000000000..cee6cb88e020 --- /dev/null +++ b/arch/sh/include/mach-migor/mach/migor.h | |||
@@ -0,0 +1,14 @@ | |||
1 | #ifndef __ASM_SH_MIGOR_H | ||
2 | #define __ASM_SH_MIGOR_H | ||
3 | |||
4 | #define PORT_MSELCRB 0xa4050182 | ||
5 | #define BSC_CS4BCR 0xfec10010 | ||
6 | #define BSC_CS6ABCR 0xfec1001c | ||
7 | #define BSC_CS4WCR 0xfec10030 | ||
8 | |||
9 | #include <video/sh_mobile_lcdc.h> | ||
10 | |||
11 | int migor_lcd_qvga_setup(void *board_data, void *sys_ops_handle, | ||
12 | struct sh_mobile_lcdc_sys_bus_ops *sys_ops); | ||
13 | |||
14 | #endif /* __ASM_SH_MIGOR_H */ | ||
diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32 index 94ed99b68002..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/ |
@@ -33,6 +33,7 @@ obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o | |||
33 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 33 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
34 | obj-$(CONFIG_DUMP_CODE) += disassemble.o | 34 | obj-$(CONFIG_DUMP_CODE) += disassemble.o |
35 | obj-$(CONFIG_HIBERNATION) += swsusp.o | 35 | obj-$(CONFIG_HIBERNATION) += swsusp.o |
36 | obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o | ||
36 | 37 | ||
37 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o | 38 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o |
38 | 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/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/shmobile/sleep.S b/arch/sh/kernel/cpu/shmobile/sleep.S index 5d888ef53d82..baf2d7d46b05 100644 --- a/arch/sh/kernel/cpu/shmobile/sleep.S +++ b/arch/sh/kernel/cpu/shmobile/sleep.S | |||
@@ -26,8 +26,30 @@ ENTRY(sh_mobile_standby) | |||
26 | 26 | ||
27 | tst #SUSP_SH_SF, r0 | 27 | tst #SUSP_SH_SF, r0 |
28 | bt skip_set_sf | 28 | bt skip_set_sf |
29 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 | ||
30 | /* DBSC: put memory in self-refresh mode */ | ||
29 | 31 | ||
30 | /* SDRAM: disable power down and put in self-refresh mode */ | 32 | mov.l dben_reg, r4 |
33 | mov.l dben_data0, r1 | ||
34 | mov.l r1, @r4 | ||
35 | |||
36 | mov.l dbrfpdn0_reg, r4 | ||
37 | mov.l dbrfpdn0_data0, r1 | ||
38 | mov.l r1, @r4 | ||
39 | |||
40 | mov.l dbcmdcnt_reg, r4 | ||
41 | mov.l dbcmdcnt_data0, r1 | ||
42 | mov.l r1, @r4 | ||
43 | |||
44 | mov.l dbcmdcnt_reg, r4 | ||
45 | mov.l dbcmdcnt_data1, r1 | ||
46 | mov.l r1, @r4 | ||
47 | |||
48 | mov.l dbrfpdn0_reg, r4 | ||
49 | mov.l dbrfpdn0_data1, r1 | ||
50 | mov.l r1, @r4 | ||
51 | #else | ||
52 | /* SBSC: disable power down and put in self-refresh mode */ | ||
31 | mov.l 1f, r4 | 53 | mov.l 1f, r4 |
32 | mov.l 2f, r1 | 54 | mov.l 2f, r1 |
33 | mov.l @r4, r2 | 55 | mov.l @r4, r2 |
@@ -35,6 +57,7 @@ ENTRY(sh_mobile_standby) | |||
35 | mov.l 3f, r3 | 57 | mov.l 3f, r3 |
36 | and r3, r2 | 58 | and r3, r2 |
37 | mov.l r2, @r4 | 59 | mov.l r2, @r4 |
60 | #endif | ||
38 | 61 | ||
39 | skip_set_sf: | 62 | skip_set_sf: |
40 | tst #SUSP_SH_SLEEP, r0 | 63 | tst #SUSP_SH_SLEEP, r0 |
@@ -84,7 +107,36 @@ done_sleep: | |||
84 | tst #SUSP_SH_SF, r0 | 107 | tst #SUSP_SH_SF, r0 |
85 | bt skip_restore_sf | 108 | bt skip_restore_sf |
86 | 109 | ||
87 | /* SDRAM: set auto-refresh mode */ | 110 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 |
111 | /* DBSC: put memory in auto-refresh mode */ | ||
112 | |||
113 | mov.l dbrfpdn0_reg, r4 | ||
114 | mov.l dbrfpdn0_data0, r1 | ||
115 | mov.l r1, @r4 | ||
116 | |||
117 | /* sleep 140 ns */ | ||
118 | nop | ||
119 | nop | ||
120 | nop | ||
121 | nop | ||
122 | |||
123 | mov.l dbcmdcnt_reg, r4 | ||
124 | mov.l dbcmdcnt_data0, r1 | ||
125 | mov.l r1, @r4 | ||
126 | |||
127 | mov.l dbcmdcnt_reg, r4 | ||
128 | mov.l dbcmdcnt_data1, r1 | ||
129 | mov.l r1, @r4 | ||
130 | |||
131 | mov.l dben_reg, r4 | ||
132 | mov.l dben_data1, r1 | ||
133 | mov.l r1, @r4 | ||
134 | |||
135 | mov.l dbrfpdn0_reg, r4 | ||
136 | mov.l dbrfpdn0_data2, r1 | ||
137 | mov.l r1, @r4 | ||
138 | #else | ||
139 | /* SBSC: set auto-refresh mode */ | ||
88 | mov.l 1f, r4 | 140 | mov.l 1f, r4 |
89 | mov.l @r4, r2 | 141 | mov.l @r4, r2 |
90 | mov.l 4f, r3 | 142 | mov.l 4f, r3 |
@@ -98,15 +150,29 @@ done_sleep: | |||
98 | add r4, r3 | 150 | add r4, r3 |
99 | or r2, r3 | 151 | or r2, r3 |
100 | mov.l r3, @r1 | 152 | mov.l r3, @r1 |
153 | #endif | ||
101 | skip_restore_sf: | 154 | skip_restore_sf: |
102 | rts | 155 | rts |
103 | nop | 156 | nop |
104 | 157 | ||
105 | .balign 4 | 158 | .balign 4 |
159 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 | ||
160 | dben_reg: .long 0xfd000010 /* DBEN */ | ||
161 | dben_data0: .long 0 | ||
162 | dben_data1: .long 1 | ||
163 | dbrfpdn0_reg: .long 0xfd000040 /* DBRFPDN0 */ | ||
164 | dbrfpdn0_data0: .long 0 | ||
165 | dbrfpdn0_data1: .long 1 | ||
166 | dbrfpdn0_data2: .long 0x00010000 | ||
167 | dbcmdcnt_reg: .long 0xfd000014 /* DBCMDCNT */ | ||
168 | dbcmdcnt_data0: .long 2 | ||
169 | dbcmdcnt_data1: .long 4 | ||
170 | #else | ||
106 | 1: .long 0xfe400008 /* SDCR0 */ | 171 | 1: .long 0xfe400008 /* SDCR0 */ |
107 | 2: .long 0x00000400 | 172 | 2: .long 0x00000400 |
108 | 3: .long 0xffff7fff | 173 | 3: .long 0xffff7fff |
109 | 4: .long 0xfffffbff | 174 | 4: .long 0xfffffbff |
175 | #endif | ||
110 | 5: .long 0xa4150020 /* STBCR */ | 176 | 5: .long 0xa4150020 /* STBCR */ |
111 | 6: .long 0xfe40001c /* RTCOR */ | 177 | 6: .long 0xfe40001c /* RTCOR */ |
112 | 7: .long 0xfe400018 /* RTCNT */ | 178 | 7: .long 0xfe400018 /* RTCNT */ |
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 64f2746baf91..81a46145ffa5 100644 --- a/arch/sh/kernel/early_printk.c +++ b/arch/sh/kernel/early_printk.c | |||
@@ -223,6 +223,7 @@ static int __init setup_early_printk(char *buf) | |||
223 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SH3) | 223 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_CPU_SH3) |
224 | scif_sercon_init(buf + 6); | 224 | scif_sercon_init(buf + 6); |
225 | #endif | 225 | #endif |
226 | #endif | ||
226 | } | 227 | } |
227 | #endif | 228 | #endif |
228 | 229 | ||
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index fc26ccd82789..e63178fefb9b 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S | |||
@@ -43,6 +43,7 @@ | |||
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 ; TRACE_IRQS_OFF | 49 | # define preempt_stop() cli ; TRACE_IRQS_OFF |
@@ -66,6 +67,11 @@ ENTRY(exception_error) | |||
66 | 67 | ||
67 | .align 2 | 68 | .align 2 |
68 | 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 | ||
69 | preempt_stop() | 75 | preempt_stop() |
70 | ENTRY(ret_from_irq) | 76 | ENTRY(ret_from_irq) |
71 | ! | 77 | ! |
@@ -240,6 +246,7 @@ debug_trap: | |||
240 | nop | 246 | nop |
241 | bra __restore_all | 247 | bra __restore_all |
242 | nop | 248 | nop |
249 | CFI_ENDPROC | ||
243 | 250 | ||
244 | .align 2 | 251 | .align 2 |
245 | 1: .long debug_trap_table | 252 | 1: .long debug_trap_table |
@@ -285,6 +292,7 @@ ret_from_fork: | |||
285 | * system calls and debug traps through their respective jump tables. | 292 | * system calls and debug traps through their respective jump tables. |
286 | */ | 293 | */ |
287 | ENTRY(system_call) | 294 | ENTRY(system_call) |
295 | setup_frame_reg | ||
288 | #if !defined(CONFIG_CPU_SH2) | 296 | #if !defined(CONFIG_CPU_SH2) |
289 | mov.l 1f, r9 | 297 | mov.l 1f, r9 |
290 | mov.l @r9, r8 ! Read from TRA (Trap Address) Register | 298 | mov.l @r9, r8 ! Read from TRA (Trap Address) Register |
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 278c68c60488..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 | ||
@@ -261,6 +262,9 @@ void __init init_IRQ(void) | |||
261 | sh_mv.mv_init_irq(); | 262 | sh_mv.mv_init_irq(); |
262 | 263 | ||
263 | 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(); | ||
264 | } | 268 | } |
265 | 269 | ||
266 | #ifdef CONFIG_SPARSE_IRQ | 270 | #ifdef CONFIG_SPARSE_IRQ |
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/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 80dc9f8d9412..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 |
@@ -70,6 +70,8 @@ SECTIONS | |||
70 | 70 | ||
71 | _edata = .; /* End of data section */ | 71 | _edata = .; /* End of data section */ |
72 | 72 | ||
73 | DWARF_EH_FRAME | ||
74 | |||
73 | . = ALIGN(PAGE_SIZE); /* Init code and data */ | 75 | . = ALIGN(PAGE_SIZE); /* Init code and data */ |
74 | __init_begin = .; | 76 | __init_begin = .; |
75 | INIT_TEXT_SECTION(PAGE_SIZE) | 77 | INIT_TEXT_SECTION(PAGE_SIZE) |
diff --git a/arch/sh/mm/ioremap_64.c b/arch/sh/mm/ioremap_64.c index 828c8597219d..b16843d02b76 100644 --- a/arch/sh/mm/ioremap_64.c +++ b/arch/sh/mm/ioremap_64.c | |||
@@ -94,7 +94,6 @@ static struct resource *shmedia_find_resource(struct resource *root, | |||
94 | static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size, | 94 | static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size, |
95 | const char *name, unsigned long flags) | 95 | const char *name, unsigned long flags) |
96 | { | 96 | { |
97 | static int printed_full; | ||
98 | struct xresource *xres; | 97 | struct xresource *xres; |
99 | struct resource *res; | 98 | struct resource *res; |
100 | char *tack; | 99 | char *tack; |
@@ -108,11 +107,8 @@ static void __iomem *shmedia_alloc_io(unsigned long phys, unsigned long size, | |||
108 | tack = xres->xname; | 107 | tack = xres->xname; |
109 | res = &xres->xres; | 108 | res = &xres->xres; |
110 | } else { | 109 | } else { |
111 | if (!printed_full) { | 110 | printk_once(KERN_NOTICE "%s: done with statics, " |
112 | printk(KERN_NOTICE "%s: done with statics, " | ||
113 | "switching to kmalloc\n", __func__); | 111 | "switching to kmalloc\n", __func__); |
114 | printed_full = 1; | ||
115 | } | ||
116 | tlen = strlen(name); | 112 | tlen = strlen(name); |
117 | tack = kmalloc(sizeof(struct resource) + tlen + 1, GFP_KERNEL); | 113 | tack = kmalloc(sizeof(struct resource) + tlen + 1, GFP_KERNEL); |
118 | if (!tack) | 114 | if (!tack) |
diff --git a/arch/sh/oprofile/backtrace.c b/arch/sh/oprofile/backtrace.c index 9499a2914f89..2bc74de23f08 100644 --- a/arch/sh/oprofile/backtrace.c +++ b/arch/sh/oprofile/backtrace.c | |||
@@ -17,9 +17,43 @@ | |||
17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
18 | #include <linux/kallsyms.h> | 18 | #include <linux/kallsyms.h> |
19 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
20 | #include <asm/unwinder.h> | ||
20 | #include <asm/ptrace.h> | 21 | #include <asm/ptrace.h> |
21 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
22 | #include <asm/sections.h> | 23 | #include <asm/sections.h> |
24 | #include <asm/stacktrace.h> | ||
25 | |||
26 | static void backtrace_warning_symbol(void *data, char *msg, | ||
27 | unsigned long symbol) | ||
28 | { | ||
29 | /* Ignore warnings */ | ||
30 | } | ||
31 | |||
32 | static void backtrace_warning(void *data, char *msg) | ||
33 | { | ||
34 | /* Ignore warnings */ | ||
35 | } | ||
36 | |||
37 | static int backtrace_stack(void *data, char *name) | ||
38 | { | ||
39 | /* Yes, we want all stacks */ | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static void backtrace_address(void *data, unsigned long addr, int reliable) | ||
44 | { | ||
45 | unsigned int *depth = data; | ||
46 | |||
47 | if ((*depth)--) | ||
48 | oprofile_add_trace(addr); | ||
49 | } | ||
50 | |||
51 | static struct stacktrace_ops backtrace_ops = { | ||
52 | .warning = backtrace_warning, | ||
53 | .warning_symbol = backtrace_warning_symbol, | ||
54 | .stack = backtrace_stack, | ||
55 | .address = backtrace_address, | ||
56 | }; | ||
23 | 57 | ||
24 | /* Limit to stop backtracing too far. */ | 58 | /* Limit to stop backtracing too far. */ |
25 | static int backtrace_limit = 20; | 59 | static int backtrace_limit = 20; |
@@ -47,50 +81,6 @@ user_backtrace(unsigned long *stackaddr, struct pt_regs *regs) | |||
47 | return stackaddr; | 81 | return stackaddr; |
48 | } | 82 | } |
49 | 83 | ||
50 | /* | ||
51 | * | | /\ Higher addresses | ||
52 | * | | | ||
53 | * --------------- stack base (address of current_thread_info) | ||
54 | * | thread info | | ||
55 | * . . | ||
56 | * | stack | | ||
57 | * --------------- saved regs->regs[15] value if valid | ||
58 | * . . | ||
59 | * --------------- struct pt_regs stored on stack (struct pt_regs *) | ||
60 | * | | | ||
61 | * . . | ||
62 | * | | | ||
63 | * --------------- ??? | ||
64 | * | | | ||
65 | * | | \/ Lower addresses | ||
66 | * | ||
67 | * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values | ||
68 | */ | ||
69 | static int valid_kernel_stack(unsigned long *stackaddr, struct pt_regs *regs) | ||
70 | { | ||
71 | unsigned long stack = (unsigned long)regs; | ||
72 | unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE; | ||
73 | |||
74 | return ((unsigned long)stackaddr > stack) && ((unsigned long)stackaddr < stack_base); | ||
75 | } | ||
76 | |||
77 | static unsigned long * | ||
78 | kernel_backtrace(unsigned long *stackaddr, struct pt_regs *regs) | ||
79 | { | ||
80 | unsigned long addr; | ||
81 | |||
82 | /* | ||
83 | * If not a valid kernel address, keep going till we find one | ||
84 | * or the SP stops being a valid address. | ||
85 | */ | ||
86 | do { | ||
87 | addr = *stackaddr++; | ||
88 | oprofile_add_trace(addr); | ||
89 | } while (valid_kernel_stack(stackaddr, regs)); | ||
90 | |||
91 | return stackaddr; | ||
92 | } | ||
93 | |||
94 | void sh_backtrace(struct pt_regs * const regs, unsigned int depth) | 84 | void sh_backtrace(struct pt_regs * const regs, unsigned int depth) |
95 | { | 85 | { |
96 | unsigned long *stackaddr; | 86 | unsigned long *stackaddr; |
@@ -103,9 +93,9 @@ void sh_backtrace(struct pt_regs * const regs, unsigned int depth) | |||
103 | 93 | ||
104 | stackaddr = (unsigned long *)regs->regs[15]; | 94 | stackaddr = (unsigned long *)regs->regs[15]; |
105 | if (!user_mode(regs)) { | 95 | if (!user_mode(regs)) { |
106 | while (depth-- && valid_kernel_stack(stackaddr, regs)) | 96 | if (depth) |
107 | stackaddr = kernel_backtrace(stackaddr, regs); | 97 | unwind_stack(NULL, regs, stackaddr, |
108 | 98 | &backtrace_ops, &depth); | |
109 | return; | 99 | return; |
110 | } | 100 | } |
111 | 101 | ||