diff options
author | David S. Miller <davem@davemloft.net> | 2009-12-11 20:12:17 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-12-11 20:12:17 -0500 |
commit | 501706565b2d4d2d40d0d301d5411ede099b8a6f (patch) | |
tree | 142a18bf1f1e74a09dbfa27540b893ade0fd797d /arch/sh | |
parent | e93737b0f0159a61772894943199fd3b6f315641 (diff) | |
parent | 2fe77b81c77eed92c4c0439f74c8148a295b4a86 (diff) |
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Conflicts:
include/net/tcp.h
Diffstat (limited to 'arch/sh')
132 files changed, 4303 insertions, 2910 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 88cdeb9f72d9..0031a6979f3a 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
@@ -16,7 +16,9 @@ config SUPERH | |||
16 | select HAVE_IOREMAP_PROT if MMU | 16 | select HAVE_IOREMAP_PROT if MMU |
17 | select HAVE_ARCH_TRACEHOOK | 17 | select HAVE_ARCH_TRACEHOOK |
18 | select HAVE_DMA_API_DEBUG | 18 | select HAVE_DMA_API_DEBUG |
19 | select HAVE_DMA_ATTRS | ||
19 | select HAVE_PERF_EVENTS | 20 | select HAVE_PERF_EVENTS |
21 | select PERF_USE_VMALLOC | ||
20 | select HAVE_KERNEL_GZIP | 22 | select HAVE_KERNEL_GZIP |
21 | select HAVE_KERNEL_BZIP2 | 23 | select HAVE_KERNEL_BZIP2 |
22 | select HAVE_KERNEL_LZMA | 24 | select HAVE_KERNEL_LZMA |
@@ -37,6 +39,7 @@ config SUPERH32 | |||
37 | select HAVE_FTRACE_MCOUNT_RECORD | 39 | select HAVE_FTRACE_MCOUNT_RECORD |
38 | select HAVE_DYNAMIC_FTRACE | 40 | select HAVE_DYNAMIC_FTRACE |
39 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST | 41 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST |
42 | select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE | ||
40 | select HAVE_FUNCTION_GRAPH_TRACER | 43 | select HAVE_FUNCTION_GRAPH_TRACER |
41 | select HAVE_ARCH_KGDB | 44 | select HAVE_ARCH_KGDB |
42 | select ARCH_HIBERNATION_POSSIBLE if MMU | 45 | select ARCH_HIBERNATION_POSSIBLE if MMU |
@@ -170,6 +173,12 @@ config ARCH_HAS_CPU_IDLE_WAIT | |||
170 | config IO_TRAPPED | 173 | config IO_TRAPPED |
171 | bool | 174 | bool |
172 | 175 | ||
176 | config DMA_COHERENT | ||
177 | bool | ||
178 | |||
179 | config DMA_NONCOHERENT | ||
180 | def_bool !DMA_COHERENT | ||
181 | |||
173 | source "init/Kconfig" | 182 | source "init/Kconfig" |
174 | 183 | ||
175 | source "kernel/Kconfig.freezer" | 184 | source "kernel/Kconfig.freezer" |
@@ -220,6 +229,7 @@ config CPU_SHX2 | |||
220 | 229 | ||
221 | config CPU_SHX3 | 230 | config CPU_SHX3 |
222 | bool | 231 | bool |
232 | select DMA_COHERENT | ||
223 | 233 | ||
224 | config ARCH_SHMOBILE | 234 | config ARCH_SHMOBILE |
225 | bool | 235 | bool |
@@ -761,17 +771,6 @@ config ENTRY_OFFSET | |||
761 | default "0x00010000" if PAGE_SIZE_64KB | 771 | default "0x00010000" if PAGE_SIZE_64KB |
762 | default "0x00000000" | 772 | default "0x00000000" |
763 | 773 | ||
764 | config UBC_WAKEUP | ||
765 | bool "Wakeup UBC on startup" | ||
766 | depends on CPU_SH4 && !CPU_SH4A | ||
767 | help | ||
768 | Selecting this option will wakeup the User Break Controller (UBC) on | ||
769 | startup. Although the UBC is left in an awake state when the processor | ||
770 | comes up, some boot loaders misbehave by putting the UBC to sleep in a | ||
771 | power saving state, which causes issues with things like ptrace(). | ||
772 | |||
773 | If unsure, say N. | ||
774 | |||
775 | choice | 774 | choice |
776 | prompt "Kernel command line" | 775 | prompt "Kernel command line" |
777 | optional | 776 | optional |
@@ -818,7 +817,13 @@ config MAPLE | |||
818 | Dreamcast with a serial line terminal or a remote network | 817 | Dreamcast with a serial line terminal or a remote network |
819 | connection. | 818 | connection. |
820 | 819 | ||
821 | source "arch/sh/drivers/pci/Kconfig" | 820 | config PCI |
821 | bool "PCI support" | ||
822 | depends on SYS_SUPPORTS_PCI | ||
823 | help | ||
824 | Find out whether you have a PCI motherboard. PCI is the name of a | ||
825 | bus system, i.e. the way the CPU talks to the other stuff inside | ||
826 | your box. If you have PCI, say Y, otherwise N. | ||
822 | 827 | ||
823 | source "drivers/pci/pcie/Kconfig" | 828 | source "drivers/pci/pcie/Kconfig" |
824 | 829 | ||
diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 66e40aabc600..ac17c5ac550e 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile | |||
@@ -78,6 +78,9 @@ defaultimage-$(CONFIG_SUPERH32) := zImage | |||
78 | defaultimage-$(CONFIG_SH_SH7785LCR) := uImage | 78 | defaultimage-$(CONFIG_SH_SH7785LCR) := uImage |
79 | defaultimage-$(CONFIG_SH_RSK) := uImage | 79 | defaultimage-$(CONFIG_SH_RSK) := uImage |
80 | defaultimage-$(CONFIG_SH_URQUELL) := uImage | 80 | defaultimage-$(CONFIG_SH_URQUELL) := uImage |
81 | defaultimage-$(CONFIG_SH_MIGOR) := uImage | ||
82 | defaultimage-$(CONFIG_SH_AP325RXA) := uImage | ||
83 | defaultimage-$(CONFIG_SH_7724_SOLUTION_ENGINE) := uImage | ||
81 | defaultimage-$(CONFIG_SH_7206_SOLUTION_ENGINE) := vmlinux | 84 | defaultimage-$(CONFIG_SH_7206_SOLUTION_ENGINE) := vmlinux |
82 | defaultimage-$(CONFIG_SH_7619_SOLUTION_ENGINE) := vmlinux | 85 | defaultimage-$(CONFIG_SH_7619_SOLUTION_ENGINE) := vmlinux |
83 | 86 | ||
@@ -136,6 +139,7 @@ machdir-$(CONFIG_SH_7751_SYSTEMH) += mach-systemh | |||
136 | machdir-$(CONFIG_SH_EDOSK7705) += mach-edosk7705 | 139 | machdir-$(CONFIG_SH_EDOSK7705) += mach-edosk7705 |
137 | machdir-$(CONFIG_SH_HIGHLANDER) += mach-highlander | 140 | machdir-$(CONFIG_SH_HIGHLANDER) += mach-highlander |
138 | machdir-$(CONFIG_SH_MIGOR) += mach-migor | 141 | machdir-$(CONFIG_SH_MIGOR) += mach-migor |
142 | machdir-$(CONFIG_SH_AP325RXA) += mach-ap325rxa | ||
139 | machdir-$(CONFIG_SH_KFR2R09) += mach-kfr2r09 | 143 | machdir-$(CONFIG_SH_KFR2R09) += mach-kfr2r09 |
140 | machdir-$(CONFIG_SH_ECOVEC) += mach-ecovec24 | 144 | machdir-$(CONFIG_SH_ECOVEC) += mach-ecovec24 |
141 | machdir-$(CONFIG_SH_SDK7780) += mach-sdk7780 | 145 | machdir-$(CONFIG_SH_SDK7780) += mach-sdk7780 |
diff --git a/arch/sh/boards/Makefile b/arch/sh/boards/Makefile index 7baa21090231..ce0f26381784 100644 --- a/arch/sh/boards/Makefile +++ b/arch/sh/boards/Makefile | |||
@@ -1,7 +1,6 @@ | |||
1 | # | 1 | # |
2 | # Specific board support, not covered by a mach group. | 2 | # Specific board support, not covered by a mach group. |
3 | # | 3 | # |
4 | obj-$(CONFIG_SH_AP325RXA) += board-ap325rxa.o | ||
5 | obj-$(CONFIG_SH_MAGIC_PANEL_R2) += board-magicpanelr2.o | 4 | obj-$(CONFIG_SH_MAGIC_PANEL_R2) += board-magicpanelr2.o |
6 | obj-$(CONFIG_SH_SH7785LCR) += board-sh7785lcr.o | 5 | obj-$(CONFIG_SH_SH7785LCR) += board-sh7785lcr.o |
7 | obj-$(CONFIG_SH_URQUELL) += board-urquell.o | 6 | obj-$(CONFIG_SH_URQUELL) += board-urquell.o |
diff --git a/arch/sh/boards/mach-ap325rxa/Makefile b/arch/sh/boards/mach-ap325rxa/Makefile new file mode 100644 index 000000000000..4cf1774d2613 --- /dev/null +++ b/arch/sh/boards/mach-ap325rxa/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-y := setup.o sdram.o | ||
2 | |||
diff --git a/arch/sh/boards/mach-ap325rxa/sdram.S b/arch/sh/boards/mach-ap325rxa/sdram.S new file mode 100644 index 000000000000..db24fbed4fca --- /dev/null +++ b/arch/sh/boards/mach-ap325rxa/sdram.S | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * AP325RXA sdram self/auto-refresh setup code | ||
3 | * | ||
4 | * Copyright (C) 2009 Magnus Damm | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/sys.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/asm-offsets.h> | ||
15 | #include <asm/suspend.h> | ||
16 | #include <asm/romimage-macros.h> | ||
17 | |||
18 | /* code to enter and leave self-refresh. must be self-contained. | ||
19 | * this code will be copied to on-chip memory and executed from there. | ||
20 | */ | ||
21 | .balign 4 | ||
22 | ENTRY(ap325rxa_sdram_enter_start) | ||
23 | |||
24 | /* SBSC: disable power down and put in self-refresh mode */ | ||
25 | mov.l 1f, r4 | ||
26 | mov.l 2f, r1 | ||
27 | mov.l @r4, r2 | ||
28 | or r1, r2 | ||
29 | mov.l 3f, r3 | ||
30 | and r3, r2 | ||
31 | mov.l r2, @r4 | ||
32 | |||
33 | rts | ||
34 | nop | ||
35 | |||
36 | .balign 4 | ||
37 | 1: .long 0xfe400008 /* SDCR0 */ | ||
38 | 2: .long 0x00000400 | ||
39 | 3: .long 0xffff7fff | ||
40 | ENTRY(ap325rxa_sdram_enter_end) | ||
41 | |||
42 | .balign 4 | ||
43 | ENTRY(ap325rxa_sdram_leave_start) | ||
44 | |||
45 | /* SBSC: set auto-refresh mode */ | ||
46 | mov.l 1f, r4 | ||
47 | mov.l @r4, r0 | ||
48 | mov.l 4f, r1 | ||
49 | and r1, r0 | ||
50 | mov.l r0, @r4 | ||
51 | mov.l 6f, r4 | ||
52 | mov.l 8f, r0 | ||
53 | mov.l @r4, r1 | ||
54 | mov #-1, r4 | ||
55 | add r4, r1 | ||
56 | or r1, r0 | ||
57 | mov.l 7f, r1 | ||
58 | mov.l r0, @r1 | ||
59 | |||
60 | rts | ||
61 | nop | ||
62 | |||
63 | .balign 4 | ||
64 | 1: .long 0xfe400008 /* SDCR0 */ | ||
65 | 4: .long 0xfffffbff | ||
66 | 6: .long 0xfe40001c /* RTCOR */ | ||
67 | 7: .long 0xfe400018 /* RTCNT */ | ||
68 | 8: .long 0xa55a0000 | ||
69 | ENTRY(ap325rxa_sdram_leave_end) | ||
diff --git a/arch/sh/boards/board-ap325rxa.c b/arch/sh/boards/mach-ap325rxa/setup.c index 2d080732a964..cf9dc12dfeb1 100644 --- a/arch/sh/boards/board-ap325rxa.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c | |||
@@ -20,8 +20,6 @@ | |||
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/smsc911x.h> | 21 | #include <linux/smsc911x.h> |
22 | #include <linux/gpio.h> | 22 | #include <linux/gpio.h> |
23 | #include <linux/spi/spi.h> | ||
24 | #include <linux/spi/spi_gpio.h> | ||
25 | #include <media/ov772x.h> | 23 | #include <media/ov772x.h> |
26 | #include <media/soc_camera.h> | 24 | #include <media/soc_camera.h> |
27 | #include <media/soc_camera_platform.h> | 25 | #include <media/soc_camera_platform.h> |
@@ -29,6 +27,7 @@ | |||
29 | #include <video/sh_mobile_lcdc.h> | 27 | #include <video/sh_mobile_lcdc.h> |
30 | #include <asm/io.h> | 28 | #include <asm/io.h> |
31 | #include <asm/clock.h> | 29 | #include <asm/clock.h> |
30 | #include <asm/suspend.h> | ||
32 | #include <cpu/sh7723.h> | 31 | #include <cpu/sh7723.h> |
33 | 32 | ||
34 | static struct smsc911x_platform_config smsc911x_config = { | 33 | static struct smsc911x_platform_config smsc911x_config = { |
@@ -409,17 +408,49 @@ static struct platform_device ceu_device = { | |||
409 | }, | 408 | }, |
410 | }; | 409 | }; |
411 | 410 | ||
412 | struct spi_gpio_platform_data sdcard_cn3_platform_data = { | 411 | static struct resource sdhi0_cn3_resources[] = { |
413 | .sck = GPIO_PTD0, | 412 | [0] = { |
414 | .mosi = GPIO_PTD1, | 413 | .name = "SDHI0", |
415 | .miso = GPIO_PTD2, | 414 | .start = 0x04ce0000, |
416 | .num_chipselect = 1, | 415 | .end = 0x04ce01ff, |
416 | .flags = IORESOURCE_MEM, | ||
417 | }, | ||
418 | [1] = { | ||
419 | .start = 101, | ||
420 | .flags = IORESOURCE_IRQ, | ||
421 | }, | ||
417 | }; | 422 | }; |
418 | 423 | ||
419 | static struct platform_device sdcard_cn3_device = { | 424 | static struct platform_device sdhi0_cn3_device = { |
420 | .name = "spi_gpio", | 425 | .name = "sh_mobile_sdhi", |
421 | .dev = { | 426 | .id = 0, /* "sdhi0" clock */ |
422 | .platform_data = &sdcard_cn3_platform_data, | 427 | .num_resources = ARRAY_SIZE(sdhi0_cn3_resources), |
428 | .resource = sdhi0_cn3_resources, | ||
429 | .archdata = { | ||
430 | .hwblk_id = HWBLK_SDHI0, | ||
431 | }, | ||
432 | }; | ||
433 | |||
434 | static struct resource sdhi1_cn7_resources[] = { | ||
435 | [0] = { | ||
436 | .name = "SDHI1", | ||
437 | .start = 0x04cf0000, | ||
438 | .end = 0x04cf01ff, | ||
439 | .flags = IORESOURCE_MEM, | ||
440 | }, | ||
441 | [1] = { | ||
442 | .start = 24, | ||
443 | .flags = IORESOURCE_IRQ, | ||
444 | }, | ||
445 | }; | ||
446 | |||
447 | static struct platform_device sdhi1_cn7_device = { | ||
448 | .name = "sh_mobile_sdhi", | ||
449 | .id = 1, /* "sdhi1" clock */ | ||
450 | .num_resources = ARRAY_SIZE(sdhi1_cn7_resources), | ||
451 | .resource = sdhi1_cn7_resources, | ||
452 | .archdata = { | ||
453 | .hwblk_id = HWBLK_SDHI1, | ||
423 | }, | 454 | }, |
424 | }; | 455 | }; |
425 | 456 | ||
@@ -470,22 +501,26 @@ static struct platform_device *ap325rxa_devices[] __initdata = { | |||
470 | &lcdc_device, | 501 | &lcdc_device, |
471 | &ceu_device, | 502 | &ceu_device, |
472 | &nand_flash_device, | 503 | &nand_flash_device, |
473 | &sdcard_cn3_device, | 504 | &sdhi0_cn3_device, |
505 | &sdhi1_cn7_device, | ||
474 | &ap325rxa_camera[0], | 506 | &ap325rxa_camera[0], |
475 | &ap325rxa_camera[1], | 507 | &ap325rxa_camera[1], |
476 | }; | 508 | }; |
477 | 509 | ||
478 | static struct spi_board_info ap325rxa_spi_devices[] = { | 510 | extern char ap325rxa_sdram_enter_start; |
479 | { | 511 | extern char ap325rxa_sdram_enter_end; |
480 | .modalias = "mmc_spi", | 512 | extern char ap325rxa_sdram_leave_start; |
481 | .max_speed_hz = 5000000, | 513 | extern char ap325rxa_sdram_leave_end; |
482 | .chip_select = 0, | ||
483 | .controller_data = (void *) GPIO_PTD5, | ||
484 | }, | ||
485 | }; | ||
486 | 514 | ||
487 | static int __init ap325rxa_devices_setup(void) | 515 | static int __init ap325rxa_devices_setup(void) |
488 | { | 516 | { |
517 | /* register board specific self-refresh code */ | ||
518 | sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF, | ||
519 | &ap325rxa_sdram_enter_start, | ||
520 | &ap325rxa_sdram_enter_end, | ||
521 | &ap325rxa_sdram_leave_start, | ||
522 | &ap325rxa_sdram_leave_end); | ||
523 | |||
489 | /* LD3 and LD4 LEDs */ | 524 | /* LD3 and LD4 LEDs */ |
490 | gpio_request(GPIO_PTX5, NULL); /* RUN */ | 525 | gpio_request(GPIO_PTX5, NULL); /* RUN */ |
491 | gpio_direction_output(GPIO_PTX5, 1); | 526 | gpio_direction_output(GPIO_PTX5, 1); |
@@ -578,12 +613,28 @@ static int __init ap325rxa_devices_setup(void) | |||
578 | 613 | ||
579 | platform_resource_setup_memory(&ceu_device, "ceu", 4 << 20); | 614 | platform_resource_setup_memory(&ceu_device, "ceu", 4 << 20); |
580 | 615 | ||
616 | /* SDHI0 - CN3 - SD CARD */ | ||
617 | gpio_request(GPIO_FN_SDHI0CD_PTD, NULL); | ||
618 | gpio_request(GPIO_FN_SDHI0WP_PTD, NULL); | ||
619 | gpio_request(GPIO_FN_SDHI0D3_PTD, NULL); | ||
620 | gpio_request(GPIO_FN_SDHI0D2_PTD, NULL); | ||
621 | gpio_request(GPIO_FN_SDHI0D1_PTD, NULL); | ||
622 | gpio_request(GPIO_FN_SDHI0D0_PTD, NULL); | ||
623 | gpio_request(GPIO_FN_SDHI0CMD_PTD, NULL); | ||
624 | gpio_request(GPIO_FN_SDHI0CLK_PTD, NULL); | ||
625 | |||
626 | /* SDHI1 - CN7 - MICRO SD CARD */ | ||
627 | gpio_request(GPIO_FN_SDHI1CD, NULL); | ||
628 | gpio_request(GPIO_FN_SDHI1D3, NULL); | ||
629 | gpio_request(GPIO_FN_SDHI1D2, NULL); | ||
630 | gpio_request(GPIO_FN_SDHI1D1, NULL); | ||
631 | gpio_request(GPIO_FN_SDHI1D0, NULL); | ||
632 | gpio_request(GPIO_FN_SDHI1CMD, NULL); | ||
633 | gpio_request(GPIO_FN_SDHI1CLK, NULL); | ||
634 | |||
581 | i2c_register_board_info(0, ap325rxa_i2c_devices, | 635 | i2c_register_board_info(0, ap325rxa_i2c_devices, |
582 | ARRAY_SIZE(ap325rxa_i2c_devices)); | 636 | ARRAY_SIZE(ap325rxa_i2c_devices)); |
583 | 637 | ||
584 | spi_register_board_info(ap325rxa_spi_devices, | ||
585 | ARRAY_SIZE(ap325rxa_spi_devices)); | ||
586 | |||
587 | return platform_add_devices(ap325rxa_devices, | 638 | return platform_add_devices(ap325rxa_devices, |
588 | ARRAY_SIZE(ap325rxa_devices)); | 639 | ARRAY_SIZE(ap325rxa_devices)); |
589 | } | 640 | } |
diff --git a/arch/sh/boards/mach-ecovec24/Makefile b/arch/sh/boards/mach-ecovec24/Makefile index 51f852151655..e69bc82208fc 100644 --- a/arch/sh/boards/mach-ecovec24/Makefile +++ b/arch/sh/boards/mach-ecovec24/Makefile | |||
@@ -6,4 +6,4 @@ | |||
6 | # for more details. | 6 | # for more details. |
7 | # | 7 | # |
8 | 8 | ||
9 | obj-y := setup.o \ No newline at end of file | 9 | obj-y := setup.o sdram.o \ No newline at end of file |
diff --git a/arch/sh/boards/mach-ecovec24/sdram.S b/arch/sh/boards/mach-ecovec24/sdram.S new file mode 100644 index 000000000000..833440044407 --- /dev/null +++ b/arch/sh/boards/mach-ecovec24/sdram.S | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Ecovec24 sdram self/auto-refresh setup code | ||
3 | * | ||
4 | * Copyright (C) 2009 Magnus Damm | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/sys.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/asm-offsets.h> | ||
15 | #include <asm/suspend.h> | ||
16 | #include <asm/romimage-macros.h> | ||
17 | |||
18 | /* code to enter and leave self-refresh. must be self-contained. | ||
19 | * this code will be copied to on-chip memory and executed from there. | ||
20 | */ | ||
21 | .balign 4 | ||
22 | ENTRY(ecovec24_sdram_enter_start) | ||
23 | |||
24 | /* DBSC: put memory in self-refresh mode */ | ||
25 | |||
26 | ED 0xFD000010, 0x00000000 /* DBEN */ | ||
27 | ED 0xFD000040, 0x00000000 /* DBRFPDN0 */ | ||
28 | ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */ | ||
29 | ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */ | ||
30 | ED 0xFD000040, 0x00000001 /* DBRFPDN0 */ | ||
31 | |||
32 | rts | ||
33 | nop | ||
34 | |||
35 | ENTRY(ecovec24_sdram_enter_end) | ||
36 | |||
37 | .balign 4 | ||
38 | ENTRY(ecovec24_sdram_leave_start) | ||
39 | |||
40 | /* DBSC: put memory in auto-refresh mode */ | ||
41 | |||
42 | ED 0xFD000040, 0x00000000 /* DBRFPDN0 */ | ||
43 | WAIT 1 | ||
44 | ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */ | ||
45 | ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */ | ||
46 | ED 0xFD000010, 0x00000001 /* DBEN */ | ||
47 | ED 0xFD000040, 0x00010000 /* DBRFPDN0 */ | ||
48 | |||
49 | rts | ||
50 | nop | ||
51 | |||
52 | ENTRY(ecovec24_sdram_leave_end) | ||
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 3b1ceb46fa54..826e62326d51 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c | |||
@@ -20,12 +20,14 @@ | |||
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/i2c/tsc2007.h> | 21 | #include <linux/i2c/tsc2007.h> |
22 | #include <linux/input.h> | 22 | #include <linux/input.h> |
23 | #include <linux/input/sh_keysc.h> | ||
24 | #include <linux/mfd/sh_mobile_sdhi.h> | ||
23 | #include <video/sh_mobile_lcdc.h> | 25 | #include <video/sh_mobile_lcdc.h> |
24 | #include <media/sh_mobile_ceu.h> | 26 | #include <media/sh_mobile_ceu.h> |
25 | #include <asm/heartbeat.h> | 27 | #include <asm/heartbeat.h> |
26 | #include <asm/sh_eth.h> | 28 | #include <asm/sh_eth.h> |
27 | #include <asm/sh_keysc.h> | ||
28 | #include <asm/clock.h> | 29 | #include <asm/clock.h> |
30 | #include <asm/suspend.h> | ||
29 | #include <cpu/sh7724.h> | 31 | #include <cpu/sh7724.h> |
30 | 32 | ||
31 | /* | 33 | /* |
@@ -147,6 +149,9 @@ static struct platform_device sh_eth_device = { | |||
147 | }, | 149 | }, |
148 | .num_resources = ARRAY_SIZE(sh_eth_resources), | 150 | .num_resources = ARRAY_SIZE(sh_eth_resources), |
149 | .resource = sh_eth_resources, | 151 | .resource = sh_eth_resources, |
152 | .archdata = { | ||
153 | .hwblk_id = HWBLK_ETHER, | ||
154 | }, | ||
150 | }; | 155 | }; |
151 | 156 | ||
152 | /* USB0 host */ | 157 | /* USB0 host */ |
@@ -185,30 +190,18 @@ static struct platform_device usb0_host_device = { | |||
185 | .resource = usb0_host_resources, | 190 | .resource = usb0_host_resources, |
186 | }; | 191 | }; |
187 | 192 | ||
188 | /* | 193 | /* USB1 host/function */ |
189 | * USB1 | ||
190 | * | ||
191 | * CN5 can use both host/function, | ||
192 | * and we can determine it by checking PTB[3] | ||
193 | * | ||
194 | * This time only USB1 host is supported. | ||
195 | */ | ||
196 | void usb1_port_power(int port, int power) | 194 | void usb1_port_power(int port, int power) |
197 | { | 195 | { |
198 | if (!gpio_get_value(GPIO_PTB3)) { | ||
199 | printk(KERN_ERR "USB1 function is not supported\n"); | ||
200 | return; | ||
201 | } | ||
202 | |||
203 | gpio_set_value(GPIO_PTB5, power); | 196 | gpio_set_value(GPIO_PTB5, power); |
204 | } | 197 | } |
205 | 198 | ||
206 | static struct r8a66597_platdata usb1_host_data = { | 199 | static struct r8a66597_platdata usb1_common_data = { |
207 | .on_chip = 1, | 200 | .on_chip = 1, |
208 | .port_power = usb1_port_power, | 201 | .port_power = usb1_port_power, |
209 | }; | 202 | }; |
210 | 203 | ||
211 | static struct resource usb1_host_resources[] = { | 204 | static struct resource usb1_common_resources[] = { |
212 | [0] = { | 205 | [0] = { |
213 | .start = 0xa4d90000, | 206 | .start = 0xa4d90000, |
214 | .end = 0xa4d90124 - 1, | 207 | .end = 0xa4d90124 - 1, |
@@ -221,16 +214,16 @@ static struct resource usb1_host_resources[] = { | |||
221 | }, | 214 | }, |
222 | }; | 215 | }; |
223 | 216 | ||
224 | static struct platform_device usb1_host_device = { | 217 | static struct platform_device usb1_common_device = { |
225 | .name = "r8a66597_hcd", | 218 | /* .name will be added in arch_setup */ |
226 | .id = 1, | 219 | .id = 1, |
227 | .dev = { | 220 | .dev = { |
228 | .dma_mask = NULL, /* not use dma */ | 221 | .dma_mask = NULL, /* not use dma */ |
229 | .coherent_dma_mask = 0xffffffff, | 222 | .coherent_dma_mask = 0xffffffff, |
230 | .platform_data = &usb1_host_data, | 223 | .platform_data = &usb1_common_data, |
231 | }, | 224 | }, |
232 | .num_resources = ARRAY_SIZE(usb1_host_resources), | 225 | .num_resources = ARRAY_SIZE(usb1_common_resources), |
233 | .resource = usb1_host_resources, | 226 | .resource = usb1_common_resources, |
234 | }; | 227 | }; |
235 | 228 | ||
236 | /* LCDC */ | 229 | /* LCDC */ |
@@ -428,16 +421,90 @@ static struct i2c_board_info ts_i2c_clients = { | |||
428 | .irq = IRQ0, | 421 | .irq = IRQ0, |
429 | }; | 422 | }; |
430 | 423 | ||
424 | /* SHDI0 */ | ||
425 | static void sdhi0_set_pwr(struct platform_device *pdev, int state) | ||
426 | { | ||
427 | gpio_set_value(GPIO_PTB6, state); | ||
428 | } | ||
429 | |||
430 | static struct sh_mobile_sdhi_info sdhi0_info = { | ||
431 | .set_pwr = sdhi0_set_pwr, | ||
432 | }; | ||
433 | |||
434 | static struct resource sdhi0_resources[] = { | ||
435 | [0] = { | ||
436 | .name = "SDHI0", | ||
437 | .start = 0x04ce0000, | ||
438 | .end = 0x04ce01ff, | ||
439 | .flags = IORESOURCE_MEM, | ||
440 | }, | ||
441 | [1] = { | ||
442 | .start = 101, | ||
443 | .flags = IORESOURCE_IRQ, | ||
444 | }, | ||
445 | }; | ||
446 | |||
447 | static struct platform_device sdhi0_device = { | ||
448 | .name = "sh_mobile_sdhi", | ||
449 | .num_resources = ARRAY_SIZE(sdhi0_resources), | ||
450 | .resource = sdhi0_resources, | ||
451 | .id = 0, | ||
452 | .dev = { | ||
453 | .platform_data = &sdhi0_info, | ||
454 | }, | ||
455 | .archdata = { | ||
456 | .hwblk_id = HWBLK_SDHI0, | ||
457 | }, | ||
458 | }; | ||
459 | |||
460 | /* SHDI1 */ | ||
461 | static void sdhi1_set_pwr(struct platform_device *pdev, int state) | ||
462 | { | ||
463 | gpio_set_value(GPIO_PTB7, state); | ||
464 | } | ||
465 | |||
466 | static struct sh_mobile_sdhi_info sdhi1_info = { | ||
467 | .set_pwr = sdhi1_set_pwr, | ||
468 | }; | ||
469 | |||
470 | static struct resource sdhi1_resources[] = { | ||
471 | [0] = { | ||
472 | .name = "SDHI1", | ||
473 | .start = 0x04cf0000, | ||
474 | .end = 0x04cf01ff, | ||
475 | .flags = IORESOURCE_MEM, | ||
476 | }, | ||
477 | [1] = { | ||
478 | .start = 24, | ||
479 | .flags = IORESOURCE_IRQ, | ||
480 | }, | ||
481 | }; | ||
482 | |||
483 | static struct platform_device sdhi1_device = { | ||
484 | .name = "sh_mobile_sdhi", | ||
485 | .num_resources = ARRAY_SIZE(sdhi1_resources), | ||
486 | .resource = sdhi1_resources, | ||
487 | .id = 1, | ||
488 | .dev = { | ||
489 | .platform_data = &sdhi1_info, | ||
490 | }, | ||
491 | .archdata = { | ||
492 | .hwblk_id = HWBLK_SDHI1, | ||
493 | }, | ||
494 | }; | ||
495 | |||
431 | static struct platform_device *ecovec_devices[] __initdata = { | 496 | static struct platform_device *ecovec_devices[] __initdata = { |
432 | &heartbeat_device, | 497 | &heartbeat_device, |
433 | &nor_flash_device, | 498 | &nor_flash_device, |
434 | &sh_eth_device, | 499 | &sh_eth_device, |
435 | &usb0_host_device, | 500 | &usb0_host_device, |
436 | &usb1_host_device, /* USB1 host support */ | 501 | &usb1_common_device, |
437 | &lcdc_device, | 502 | &lcdc_device, |
438 | &ceu0_device, | 503 | &ceu0_device, |
439 | &ceu1_device, | 504 | &ceu1_device, |
440 | &keysc_device, | 505 | &keysc_device, |
506 | &sdhi0_device, | ||
507 | &sdhi1_device, | ||
441 | }; | 508 | }; |
442 | 509 | ||
443 | #define EEPROM_ADDR 0x50 | 510 | #define EEPROM_ADDR 0x50 |
@@ -466,12 +533,9 @@ static u8 mac_read(struct i2c_adapter *a, u8 command) | |||
466 | return buf; | 533 | return buf; |
467 | } | 534 | } |
468 | 535 | ||
469 | #define MAC_LEN 6 | 536 | static void __init sh_eth_init(struct sh_eth_plat_data *pd) |
470 | static void __init sh_eth_init(void) | ||
471 | { | 537 | { |
472 | struct i2c_adapter *a = i2c_get_adapter(1); | 538 | struct i2c_adapter *a = i2c_get_adapter(1); |
473 | struct clk *eth_clk; | ||
474 | u8 mac[MAC_LEN]; | ||
475 | int i; | 539 | int i; |
476 | 540 | ||
477 | if (!a) { | 541 | if (!a) { |
@@ -479,39 +543,30 @@ static void __init sh_eth_init(void) | |||
479 | return; | 543 | return; |
480 | } | 544 | } |
481 | 545 | ||
482 | eth_clk = clk_get(NULL, "eth0"); | ||
483 | if (!eth_clk) { | ||
484 | pr_err("can not get eth0 clk\n"); | ||
485 | return; | ||
486 | } | ||
487 | |||
488 | /* read MAC address frome EEPROM */ | 546 | /* read MAC address frome EEPROM */ |
489 | for (i = 0; i < MAC_LEN; i++) { | 547 | for (i = 0; i < sizeof(pd->mac_addr); i++) { |
490 | mac[i] = mac_read(a, 0x10 + i); | 548 | pd->mac_addr[i] = mac_read(a, 0x10 + i); |
491 | msleep(10); | 549 | msleep(10); |
492 | } | 550 | } |
493 | |||
494 | /* clock enable */ | ||
495 | clk_enable(eth_clk); | ||
496 | |||
497 | /* reset sh-eth */ | ||
498 | ctrl_outl(0x1, SH_ETH_ADDR + 0x0); | ||
499 | |||
500 | /* set MAC addr */ | ||
501 | ctrl_outl((mac[0] << 24) | | ||
502 | (mac[1] << 16) | | ||
503 | (mac[2] << 8) | | ||
504 | (mac[3] << 0), SH_ETH_MAHR); | ||
505 | ctrl_outl((mac[4] << 8) | | ||
506 | (mac[5] << 0), SH_ETH_MALR); | ||
507 | |||
508 | clk_put(eth_clk); | ||
509 | } | 551 | } |
510 | 552 | ||
511 | #define PORT_HIZA 0xA4050158 | 553 | #define PORT_HIZA 0xA4050158 |
512 | #define IODRIVEA 0xA405018A | 554 | #define IODRIVEA 0xA405018A |
555 | |||
556 | extern char ecovec24_sdram_enter_start; | ||
557 | extern char ecovec24_sdram_enter_end; | ||
558 | extern char ecovec24_sdram_leave_start; | ||
559 | extern char ecovec24_sdram_leave_end; | ||
560 | |||
513 | static int __init arch_setup(void) | 561 | static int __init arch_setup(void) |
514 | { | 562 | { |
563 | /* register board specific self-refresh code */ | ||
564 | sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF, | ||
565 | &ecovec24_sdram_enter_start, | ||
566 | &ecovec24_sdram_enter_end, | ||
567 | &ecovec24_sdram_leave_start, | ||
568 | &ecovec24_sdram_leave_end); | ||
569 | |||
515 | /* enable STATUS0, STATUS2 and PDSTATUS */ | 570 | /* enable STATUS0, STATUS2 and PDSTATUS */ |
516 | gpio_request(GPIO_FN_STATUS0, NULL); | 571 | gpio_request(GPIO_FN_STATUS0, NULL); |
517 | gpio_request(GPIO_FN_STATUS2, NULL); | 572 | gpio_request(GPIO_FN_STATUS2, NULL); |
@@ -561,6 +616,14 @@ static int __init arch_setup(void) | |||
561 | ctrl_outw(0x0600, 0xa40501d4); | 616 | ctrl_outw(0x0600, 0xa40501d4); |
562 | ctrl_outw(0x0600, 0xa4050192); | 617 | ctrl_outw(0x0600, 0xa4050192); |
563 | 618 | ||
619 | if (gpio_get_value(GPIO_PTB3)) { | ||
620 | printk(KERN_INFO "USB1 function is selected\n"); | ||
621 | usb1_common_device.name = "r8a66597_udc"; | ||
622 | } else { | ||
623 | printk(KERN_INFO "USB1 host is selected\n"); | ||
624 | usb1_common_device.name = "r8a66597_hcd"; | ||
625 | } | ||
626 | |||
564 | /* enable LCDC */ | 627 | /* enable LCDC */ |
565 | gpio_request(GPIO_FN_LCDD23, NULL); | 628 | gpio_request(GPIO_FN_LCDD23, NULL); |
566 | gpio_request(GPIO_FN_LCDD22, NULL); | 629 | gpio_request(GPIO_FN_LCDD22, NULL); |
@@ -603,8 +666,8 @@ static int __init arch_setup(void) | |||
603 | gpio_direction_output(GPIO_PTR1, 0); | 666 | gpio_direction_output(GPIO_PTR1, 0); |
604 | gpio_direction_output(GPIO_PTA2, 0); | 667 | gpio_direction_output(GPIO_PTA2, 0); |
605 | 668 | ||
606 | /* I/O buffer drive ability is low */ | 669 | /* I/O buffer drive ability is high */ |
607 | ctrl_outw((ctrl_inw(IODRIVEA) & ~0x00c0) | 0x0040 , IODRIVEA); | 670 | ctrl_outw((ctrl_inw(IODRIVEA) & ~0x00c0) | 0x0080 , IODRIVEA); |
608 | 671 | ||
609 | if (gpio_get_value(GPIO_PTE6)) { | 672 | if (gpio_get_value(GPIO_PTE6)) { |
610 | /* DVI */ | 673 | /* DVI */ |
@@ -710,6 +773,33 @@ static int __init arch_setup(void) | |||
710 | gpio_direction_input(GPIO_PTR5); | 773 | gpio_direction_input(GPIO_PTR5); |
711 | gpio_direction_input(GPIO_PTR6); | 774 | gpio_direction_input(GPIO_PTR6); |
712 | 775 | ||
776 | /* enable SDHI0 (needs DS2.4 set to ON) */ | ||
777 | gpio_request(GPIO_FN_SDHI0CD, NULL); | ||
778 | gpio_request(GPIO_FN_SDHI0WP, NULL); | ||
779 | gpio_request(GPIO_FN_SDHI0CMD, NULL); | ||
780 | gpio_request(GPIO_FN_SDHI0CLK, NULL); | ||
781 | gpio_request(GPIO_FN_SDHI0D3, NULL); | ||
782 | gpio_request(GPIO_FN_SDHI0D2, NULL); | ||
783 | gpio_request(GPIO_FN_SDHI0D1, NULL); | ||
784 | gpio_request(GPIO_FN_SDHI0D0, NULL); | ||
785 | gpio_request(GPIO_PTB6, NULL); | ||
786 | gpio_direction_output(GPIO_PTB6, 0); | ||
787 | |||
788 | /* enable SDHI1 (needs DS2.6,7 set to ON,OFF) */ | ||
789 | gpio_request(GPIO_FN_SDHI1CD, NULL); | ||
790 | gpio_request(GPIO_FN_SDHI1WP, NULL); | ||
791 | gpio_request(GPIO_FN_SDHI1CMD, NULL); | ||
792 | gpio_request(GPIO_FN_SDHI1CLK, NULL); | ||
793 | gpio_request(GPIO_FN_SDHI1D3, NULL); | ||
794 | gpio_request(GPIO_FN_SDHI1D2, NULL); | ||
795 | gpio_request(GPIO_FN_SDHI1D1, NULL); | ||
796 | gpio_request(GPIO_FN_SDHI1D0, NULL); | ||
797 | gpio_request(GPIO_PTB7, NULL); | ||
798 | gpio_direction_output(GPIO_PTB7, 0); | ||
799 | |||
800 | /* I/O buffer drive ability is high for SDHI1 */ | ||
801 | ctrl_outw((ctrl_inw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA); | ||
802 | |||
713 | /* enable I2C device */ | 803 | /* enable I2C device */ |
714 | i2c_register_board_info(1, i2c1_devices, | 804 | i2c_register_board_info(1, i2c1_devices, |
715 | ARRAY_SIZE(i2c1_devices)); | 805 | ARRAY_SIZE(i2c1_devices)); |
@@ -721,12 +811,11 @@ arch_initcall(arch_setup); | |||
721 | 811 | ||
722 | static int __init devices_setup(void) | 812 | static int __init devices_setup(void) |
723 | { | 813 | { |
724 | sh_eth_init(); | 814 | sh_eth_init(&sh_eth_plat); |
725 | return 0; | 815 | return 0; |
726 | } | 816 | } |
727 | device_initcall(devices_setup); | 817 | device_initcall(devices_setup); |
728 | 818 | ||
729 | |||
730 | static struct sh_machine_vector mv_ecovec __initmv = { | 819 | static struct sh_machine_vector mv_ecovec __initmv = { |
731 | .mv_name = "R0P7724 (EcoVec)", | 820 | .mv_name = "R0P7724 (EcoVec)", |
732 | }; | 821 | }; |
diff --git a/arch/sh/boards/mach-highlander/setup.c b/arch/sh/boards/mach-highlander/setup.c index 566e69d8d729..f663c14d8885 100644 --- a/arch/sh/boards/mach-highlander/setup.c +++ b/arch/sh/boards/mach-highlander/setup.c | |||
@@ -384,7 +384,7 @@ static unsigned char irl2irq[HL_NR_IRL]; | |||
384 | 384 | ||
385 | static int highlander_irq_demux(int irq) | 385 | static int highlander_irq_demux(int irq) |
386 | { | 386 | { |
387 | if (irq >= HL_NR_IRL || !irl2irq[irq]) | 387 | if (irq >= HL_NR_IRL || irq < 0 || !irl2irq[irq]) |
388 | return irq; | 388 | return irq; |
389 | 389 | ||
390 | return irl2irq[irq]; | 390 | return irl2irq[irq]; |
diff --git a/arch/sh/boards/mach-kfr2r09/Makefile b/arch/sh/boards/mach-kfr2r09/Makefile index 5d5867826e3b..4e577a3bf658 100644 --- a/arch/sh/boards/mach-kfr2r09/Makefile +++ b/arch/sh/boards/mach-kfr2r09/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | obj-y := setup.o | 1 | obj-y := setup.o sdram.o |
2 | obj-$(CONFIG_FB_SH_MOBILE_LCDC) += lcd_wqvga.o | 2 | obj-$(CONFIG_FB_SH_MOBILE_LCDC) += lcd_wqvga.o |
diff --git a/arch/sh/boards/mach-kfr2r09/sdram.S b/arch/sh/boards/mach-kfr2r09/sdram.S new file mode 100644 index 000000000000..0c9f55bec2fe --- /dev/null +++ b/arch/sh/boards/mach-kfr2r09/sdram.S | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * KFR2R09 sdram self/auto-refresh setup code | ||
3 | * | ||
4 | * Copyright (C) 2009 Magnus Damm | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/sys.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/asm-offsets.h> | ||
15 | #include <asm/suspend.h> | ||
16 | #include <asm/romimage-macros.h> | ||
17 | |||
18 | /* code to enter and leave self-refresh. must be self-contained. | ||
19 | * this code will be copied to on-chip memory and executed from there. | ||
20 | */ | ||
21 | .balign 4 | ||
22 | ENTRY(kfr2r09_sdram_enter_start) | ||
23 | |||
24 | /* DBSC: put memory in self-refresh mode */ | ||
25 | |||
26 | ED 0xFD000010, 0x00000000 /* DBEN */ | ||
27 | ED 0xFD000040, 0x00000000 /* DBRFPDN0 */ | ||
28 | ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */ | ||
29 | ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */ | ||
30 | ED 0xFD000040, 0x00000001 /* DBRFPDN0 */ | ||
31 | |||
32 | rts | ||
33 | nop | ||
34 | |||
35 | ENTRY(kfr2r09_sdram_enter_end) | ||
36 | |||
37 | .balign 4 | ||
38 | ENTRY(kfr2r09_sdram_leave_start) | ||
39 | |||
40 | /* DBSC: put memory in auto-refresh mode */ | ||
41 | |||
42 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
43 | tst #SUSP_SH_RSTANDBY, r0 | ||
44 | bf resume_rstandby | ||
45 | |||
46 | ED 0xFD000040, 0x00000000 /* DBRFPDN0 */ | ||
47 | WAIT 1 | ||
48 | ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */ | ||
49 | ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */ | ||
50 | ED 0xFD000010, 0x00000001 /* DBEN */ | ||
51 | ED 0xFD000040, 0x00010000 /* DBRFPDN0 */ | ||
52 | |||
53 | rts | ||
54 | nop | ||
55 | |||
56 | resume_rstandby: | ||
57 | |||
58 | /* DBSC: re-initialize and put in auto-refresh */ | ||
59 | |||
60 | ED 0xFD000108, 0x40000301 /* DBPDCNT0 */ | ||
61 | ED 0xFD000020, 0x011B0002 /* DBCONF */ | ||
62 | ED 0xFD000030, 0x03060E02 /* DBTR0 */ | ||
63 | ED 0xFD000034, 0x01020102 /* DBTR1 */ | ||
64 | ED 0xFD000038, 0x01090406 /* DBTR2 */ | ||
65 | ED 0xFD000008, 0x00000004 /* DBKIND */ | ||
66 | ED 0xFD000040, 0x00000001 /* DBRFPDN0 */ | ||
67 | ED 0xFD000040, 0x00000000 /* DBRFPDN0 */ | ||
68 | ED 0xFD000018, 0x00000001 /* DBCKECNT */ | ||
69 | WAIT 1 | ||
70 | ED 0xFD000010, 0x00000001 /* DBEN */ | ||
71 | ED 0xFD000044, 0x000004AF /* DBRFPDN1 */ | ||
72 | ED 0xFD000048, 0x20CF0037 /* DBRFPDN2 */ | ||
73 | ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */ | ||
74 | ED 0xFD000108, 0x40000300 /* DBPDCNT0 */ | ||
75 | ED 0xFD000040, 0x00010000 /* DBRFPDN0 */ | ||
76 | |||
77 | rts | ||
78 | nop | ||
79 | |||
80 | ENTRY(kfr2r09_sdram_leave_end) | ||
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index c08d33fe2104..87438d6603d6 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c | |||
@@ -16,13 +16,16 @@ | |||
16 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
17 | #include <linux/gpio.h> | 17 | #include <linux/gpio.h> |
18 | #include <linux/input.h> | 18 | #include <linux/input.h> |
19 | #include <linux/input/sh_keysc.h> | ||
19 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
20 | #include <linux/usb/r8a66597.h> | 21 | #include <linux/usb/r8a66597.h> |
22 | #include <media/soc_camera.h> | ||
23 | #include <media/sh_mobile_ceu.h> | ||
21 | #include <video/sh_mobile_lcdc.h> | 24 | #include <video/sh_mobile_lcdc.h> |
25 | #include <asm/suspend.h> | ||
22 | #include <asm/clock.h> | 26 | #include <asm/clock.h> |
23 | #include <asm/machvec.h> | 27 | #include <asm/machvec.h> |
24 | #include <asm/io.h> | 28 | #include <asm/io.h> |
25 | #include <asm/sh_keysc.h> | ||
26 | #include <cpu/sh7724.h> | 29 | #include <cpu/sh7724.h> |
27 | #include <mach/kfr2r09.h> | 30 | #include <mach/kfr2r09.h> |
28 | 31 | ||
@@ -212,11 +215,154 @@ static struct platform_device kfr2r09_usb0_gadget_device = { | |||
212 | .resource = kfr2r09_usb0_gadget_resources, | 215 | .resource = kfr2r09_usb0_gadget_resources, |
213 | }; | 216 | }; |
214 | 217 | ||
218 | static struct sh_mobile_ceu_info sh_mobile_ceu_info = { | ||
219 | .flags = SH_CEU_FLAG_USE_8BIT_BUS, | ||
220 | }; | ||
221 | |||
222 | static struct resource kfr2r09_ceu_resources[] = { | ||
223 | [0] = { | ||
224 | .name = "CEU", | ||
225 | .start = 0xfe910000, | ||
226 | .end = 0xfe91009f, | ||
227 | .flags = IORESOURCE_MEM, | ||
228 | }, | ||
229 | [1] = { | ||
230 | .start = 52, | ||
231 | .end = 52, | ||
232 | .flags = IORESOURCE_IRQ, | ||
233 | }, | ||
234 | [2] = { | ||
235 | /* place holder for contiguous memory */ | ||
236 | }, | ||
237 | }; | ||
238 | |||
239 | static struct platform_device kfr2r09_ceu_device = { | ||
240 | .name = "sh_mobile_ceu", | ||
241 | .id = 0, /* "ceu0" clock */ | ||
242 | .num_resources = ARRAY_SIZE(kfr2r09_ceu_resources), | ||
243 | .resource = kfr2r09_ceu_resources, | ||
244 | .dev = { | ||
245 | .platform_data = &sh_mobile_ceu_info, | ||
246 | }, | ||
247 | .archdata = { | ||
248 | .hwblk_id = HWBLK_CEU0, | ||
249 | }, | ||
250 | }; | ||
251 | |||
252 | static struct i2c_board_info kfr2r09_i2c_camera = { | ||
253 | I2C_BOARD_INFO("rj54n1cb0c", 0x50), | ||
254 | }; | ||
255 | |||
256 | static struct clk *camera_clk; | ||
257 | |||
258 | #define DRVCRB 0xA405018C | ||
259 | static int camera_power(struct device *dev, int mode) | ||
260 | { | ||
261 | int ret; | ||
262 | |||
263 | if (mode) { | ||
264 | long rate; | ||
265 | |||
266 | camera_clk = clk_get(NULL, "video_clk"); | ||
267 | if (IS_ERR(camera_clk)) | ||
268 | return PTR_ERR(camera_clk); | ||
269 | |||
270 | /* set VIO_CKO clock to 25MHz */ | ||
271 | rate = clk_round_rate(camera_clk, 25000000); | ||
272 | ret = clk_set_rate(camera_clk, rate); | ||
273 | if (ret < 0) | ||
274 | goto eclkrate; | ||
275 | |||
276 | /* set DRVCRB | ||
277 | * | ||
278 | * use 1.8 V for VccQ_VIO | ||
279 | * use 2.85V for VccQ_SR | ||
280 | */ | ||
281 | ctrl_outw((ctrl_inw(DRVCRB) & ~0x0003) | 0x0001, DRVCRB); | ||
282 | |||
283 | /* reset clear */ | ||
284 | ret = gpio_request(GPIO_PTB4, NULL); | ||
285 | if (ret < 0) | ||
286 | goto eptb4; | ||
287 | ret = gpio_request(GPIO_PTB7, NULL); | ||
288 | if (ret < 0) | ||
289 | goto eptb7; | ||
290 | |||
291 | ret = gpio_direction_output(GPIO_PTB4, 1); | ||
292 | if (!ret) | ||
293 | ret = gpio_direction_output(GPIO_PTB7, 1); | ||
294 | if (ret < 0) | ||
295 | goto egpioout; | ||
296 | msleep(1); | ||
297 | |||
298 | ret = clk_enable(camera_clk); /* start VIO_CKO */ | ||
299 | if (ret < 0) | ||
300 | goto eclkon; | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | ret = 0; | ||
306 | |||
307 | clk_disable(camera_clk); | ||
308 | eclkon: | ||
309 | gpio_set_value(GPIO_PTB7, 0); | ||
310 | egpioout: | ||
311 | gpio_set_value(GPIO_PTB4, 0); | ||
312 | gpio_free(GPIO_PTB7); | ||
313 | eptb7: | ||
314 | gpio_free(GPIO_PTB4); | ||
315 | eptb4: | ||
316 | eclkrate: | ||
317 | clk_put(camera_clk); | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | static struct soc_camera_link rj54n1_link = { | ||
322 | .power = camera_power, | ||
323 | .board_info = &kfr2r09_i2c_camera, | ||
324 | .i2c_adapter_id = 1, | ||
325 | .module_name = "rj54n1cb0c", | ||
326 | }; | ||
327 | |||
328 | static struct platform_device kfr2r09_camera = { | ||
329 | .name = "soc-camera-pdrv", | ||
330 | .id = 0, | ||
331 | .dev = { | ||
332 | .platform_data = &rj54n1_link, | ||
333 | }, | ||
334 | }; | ||
335 | |||
336 | static struct resource kfr2r09_sh_sdhi0_resources[] = { | ||
337 | [0] = { | ||
338 | .name = "SDHI0", | ||
339 | .start = 0x04ce0000, | ||
340 | .end = 0x04ce01ff, | ||
341 | .flags = IORESOURCE_MEM, | ||
342 | }, | ||
343 | [1] = { | ||
344 | .start = 101, | ||
345 | .flags = IORESOURCE_IRQ, | ||
346 | }, | ||
347 | }; | ||
348 | |||
349 | static struct platform_device kfr2r09_sh_sdhi0_device = { | ||
350 | .name = "sh_mobile_sdhi", | ||
351 | .num_resources = ARRAY_SIZE(kfr2r09_sh_sdhi0_resources), | ||
352 | .resource = kfr2r09_sh_sdhi0_resources, | ||
353 | .archdata = { | ||
354 | .hwblk_id = HWBLK_SDHI0, | ||
355 | }, | ||
356 | }; | ||
357 | |||
215 | static struct platform_device *kfr2r09_devices[] __initdata = { | 358 | static struct platform_device *kfr2r09_devices[] __initdata = { |
216 | &kfr2r09_nor_flash_device, | 359 | &kfr2r09_nor_flash_device, |
217 | &kfr2r09_nand_flash_device, | 360 | &kfr2r09_nand_flash_device, |
218 | &kfr2r09_sh_keysc_device, | 361 | &kfr2r09_sh_keysc_device, |
219 | &kfr2r09_sh_lcdc_device, | 362 | &kfr2r09_sh_lcdc_device, |
363 | &kfr2r09_ceu_device, | ||
364 | &kfr2r09_camera, | ||
365 | &kfr2r09_sh_sdhi0_device, | ||
220 | }; | 366 | }; |
221 | 367 | ||
222 | #define BSC_CS0BCR 0xfec10004 | 368 | #define BSC_CS0BCR 0xfec10004 |
@@ -268,11 +414,59 @@ static int kfr2r09_usb0_gadget_i2c_setup(void) | |||
268 | 414 | ||
269 | return 0; | 415 | return 0; |
270 | } | 416 | } |
417 | |||
418 | static int kfr2r09_serial_i2c_setup(void) | ||
419 | { | ||
420 | struct i2c_adapter *a; | ||
421 | struct i2c_msg msg; | ||
422 | unsigned char buf[2]; | ||
423 | int ret; | ||
424 | |||
425 | a = i2c_get_adapter(0); | ||
426 | if (!a) | ||
427 | return -ENODEV; | ||
428 | |||
429 | /* set bit 6 (the 7th bit) of chip at 0x09, register 0x13 */ | ||
430 | buf[0] = 0x13; | ||
431 | msg.addr = 0x09; | ||
432 | msg.buf = buf; | ||
433 | msg.len = 1; | ||
434 | msg.flags = 0; | ||
435 | ret = i2c_transfer(a, &msg, 1); | ||
436 | if (ret != 1) | ||
437 | return -ENODEV; | ||
438 | |||
439 | buf[0] = 0; | ||
440 | msg.addr = 0x09; | ||
441 | msg.buf = buf; | ||
442 | msg.len = 1; | ||
443 | msg.flags = I2C_M_RD; | ||
444 | ret = i2c_transfer(a, &msg, 1); | ||
445 | if (ret != 1) | ||
446 | return -ENODEV; | ||
447 | |||
448 | buf[1] = buf[0] | (1 << 6); | ||
449 | buf[0] = 0x13; | ||
450 | msg.addr = 0x09; | ||
451 | msg.buf = buf; | ||
452 | msg.len = 2; | ||
453 | msg.flags = 0; | ||
454 | ret = i2c_transfer(a, &msg, 1); | ||
455 | if (ret != 1) | ||
456 | return -ENODEV; | ||
457 | |||
458 | return 0; | ||
459 | } | ||
271 | #else | 460 | #else |
272 | static int kfr2r09_usb0_gadget_i2c_setup(void) | 461 | static int kfr2r09_usb0_gadget_i2c_setup(void) |
273 | { | 462 | { |
274 | return -ENODEV; | 463 | return -ENODEV; |
275 | } | 464 | } |
465 | |||
466 | static int kfr2r09_serial_i2c_setup(void) | ||
467 | { | ||
468 | return -ENODEV; | ||
469 | } | ||
276 | #endif | 470 | #endif |
277 | 471 | ||
278 | static int kfr2r09_usb0_gadget_setup(void) | 472 | static int kfr2r09_usb0_gadget_setup(void) |
@@ -299,11 +493,27 @@ static int kfr2r09_usb0_gadget_setup(void) | |||
299 | return 0; | 493 | return 0; |
300 | } | 494 | } |
301 | 495 | ||
496 | extern char kfr2r09_sdram_enter_start; | ||
497 | extern char kfr2r09_sdram_enter_end; | ||
498 | extern char kfr2r09_sdram_leave_start; | ||
499 | extern char kfr2r09_sdram_leave_end; | ||
500 | |||
302 | static int __init kfr2r09_devices_setup(void) | 501 | static int __init kfr2r09_devices_setup(void) |
303 | { | 502 | { |
503 | /* register board specific self-refresh code */ | ||
504 | sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF | | ||
505 | SUSP_SH_RSTANDBY, | ||
506 | &kfr2r09_sdram_enter_start, | ||
507 | &kfr2r09_sdram_enter_end, | ||
508 | &kfr2r09_sdram_leave_start, | ||
509 | &kfr2r09_sdram_leave_end); | ||
510 | |||
304 | /* enable SCIF1 serial port for YC401 console support */ | 511 | /* enable SCIF1 serial port for YC401 console support */ |
305 | gpio_request(GPIO_FN_SCIF1_RXD, NULL); | 512 | gpio_request(GPIO_FN_SCIF1_RXD, NULL); |
306 | gpio_request(GPIO_FN_SCIF1_TXD, NULL); | 513 | gpio_request(GPIO_FN_SCIF1_TXD, NULL); |
514 | kfr2r09_serial_i2c_setup(); /* ECONTMSK(bit6=L10ONEN) set 1 */ | ||
515 | gpio_request(GPIO_PTG3, NULL); /* HPON_ON */ | ||
516 | gpio_direction_output(GPIO_PTG3, 1); /* HPON_ON = H */ | ||
307 | 517 | ||
308 | /* setup NOR flash at CS0 */ | 518 | /* setup NOR flash at CS0 */ |
309 | ctrl_outl(0x36db0400, BSC_CS0BCR); | 519 | ctrl_outl(0x36db0400, BSC_CS0BCR); |
@@ -361,6 +571,32 @@ static int __init kfr2r09_devices_setup(void) | |||
361 | if (kfr2r09_usb0_gadget_setup() == 0) | 571 | if (kfr2r09_usb0_gadget_setup() == 0) |
362 | platform_device_register(&kfr2r09_usb0_gadget_device); | 572 | platform_device_register(&kfr2r09_usb0_gadget_device); |
363 | 573 | ||
574 | /* CEU */ | ||
575 | gpio_request(GPIO_FN_VIO_CKO, NULL); | ||
576 | gpio_request(GPIO_FN_VIO0_CLK, NULL); | ||
577 | gpio_request(GPIO_FN_VIO0_VD, NULL); | ||
578 | gpio_request(GPIO_FN_VIO0_HD, NULL); | ||
579 | gpio_request(GPIO_FN_VIO0_FLD, NULL); | ||
580 | gpio_request(GPIO_FN_VIO0_D7, NULL); | ||
581 | gpio_request(GPIO_FN_VIO0_D6, NULL); | ||
582 | gpio_request(GPIO_FN_VIO0_D5, NULL); | ||
583 | gpio_request(GPIO_FN_VIO0_D4, NULL); | ||
584 | gpio_request(GPIO_FN_VIO0_D3, NULL); | ||
585 | gpio_request(GPIO_FN_VIO0_D2, NULL); | ||
586 | gpio_request(GPIO_FN_VIO0_D1, NULL); | ||
587 | gpio_request(GPIO_FN_VIO0_D0, NULL); | ||
588 | |||
589 | platform_resource_setup_memory(&kfr2r09_ceu_device, "ceu", 4 << 20); | ||
590 | |||
591 | /* SDHI0 connected to yc304 */ | ||
592 | gpio_request(GPIO_FN_SDHI0CD, NULL); | ||
593 | gpio_request(GPIO_FN_SDHI0D3, NULL); | ||
594 | gpio_request(GPIO_FN_SDHI0D2, NULL); | ||
595 | gpio_request(GPIO_FN_SDHI0D1, NULL); | ||
596 | gpio_request(GPIO_FN_SDHI0D0, NULL); | ||
597 | gpio_request(GPIO_FN_SDHI0CMD, NULL); | ||
598 | gpio_request(GPIO_FN_SDHI0CLK, NULL); | ||
599 | |||
364 | return platform_add_devices(kfr2r09_devices, | 600 | return platform_add_devices(kfr2r09_devices, |
365 | ARRAY_SIZE(kfr2r09_devices)); | 601 | ARRAY_SIZE(kfr2r09_devices)); |
366 | } | 602 | } |
diff --git a/arch/sh/boards/mach-migor/Makefile b/arch/sh/boards/mach-migor/Makefile index 5f231dd25c0e..4601a89e5ac7 100644 --- a/arch/sh/boards/mach-migor/Makefile +++ b/arch/sh/boards/mach-migor/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | obj-y := setup.o | 1 | obj-y := setup.o sdram.o |
2 | obj-$(CONFIG_SH_MIGOR_QVGA) += lcd_qvga.o | 2 | obj-$(CONFIG_SH_MIGOR_QVGA) += lcd_qvga.o |
diff --git a/arch/sh/boards/mach-migor/sdram.S b/arch/sh/boards/mach-migor/sdram.S new file mode 100644 index 000000000000..614aa3a1398c --- /dev/null +++ b/arch/sh/boards/mach-migor/sdram.S | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Migo-R sdram self/auto-refresh setup code | ||
3 | * | ||
4 | * Copyright (C) 2009 Magnus Damm | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/sys.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/asm-offsets.h> | ||
15 | #include <asm/suspend.h> | ||
16 | #include <asm/romimage-macros.h> | ||
17 | |||
18 | /* code to enter and leave self-refresh. must be self-contained. | ||
19 | * this code will be copied to on-chip memory and executed from there. | ||
20 | */ | ||
21 | .balign 4 | ||
22 | ENTRY(migor_sdram_enter_start) | ||
23 | |||
24 | /* SBSC: disable power down and put in self-refresh mode */ | ||
25 | mov.l 1f, r4 | ||
26 | mov.l 2f, r1 | ||
27 | mov.l @r4, r2 | ||
28 | or r1, r2 | ||
29 | mov.l 3f, r3 | ||
30 | and r3, r2 | ||
31 | mov.l r2, @r4 | ||
32 | |||
33 | rts | ||
34 | nop | ||
35 | |||
36 | .balign 4 | ||
37 | 1: .long 0xfe400008 /* SDCR0 */ | ||
38 | 2: .long 0x00000400 | ||
39 | 3: .long 0xffff7fff | ||
40 | ENTRY(migor_sdram_enter_end) | ||
41 | |||
42 | .balign 4 | ||
43 | ENTRY(migor_sdram_leave_start) | ||
44 | |||
45 | /* SBSC: set auto-refresh mode */ | ||
46 | mov.l 1f, r4 | ||
47 | mov.l @r4, r0 | ||
48 | mov.l 4f, r1 | ||
49 | and r1, r0 | ||
50 | mov.l r0, @r4 | ||
51 | mov.l 6f, r4 | ||
52 | mov.l 8f, r0 | ||
53 | mov.l @r4, r1 | ||
54 | mov #-1, r4 | ||
55 | add r4, r1 | ||
56 | or r1, r0 | ||
57 | mov.l 7f, r1 | ||
58 | mov.l r0, @r1 | ||
59 | |||
60 | rts | ||
61 | nop | ||
62 | |||
63 | .balign 4 | ||
64 | 1: .long 0xfe400008 /* SDCR0 */ | ||
65 | 4: .long 0xfffffbff | ||
66 | 6: .long 0xfe40001c /* RTCOR */ | ||
67 | 7: .long 0xfe400018 /* RTCNT */ | ||
68 | 8: .long 0xa55a0000 | ||
69 | ENTRY(migor_sdram_leave_end) | ||
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 6ed1fd32369e..9099b6da9957 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c | |||
@@ -11,6 +11,7 @@ | |||
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/input.h> | 13 | #include <linux/input.h> |
14 | #include <linux/input/sh_keysc.h> | ||
14 | #include <linux/mtd/physmap.h> | 15 | #include <linux/mtd/physmap.h> |
15 | #include <linux/mtd/nand.h> | 16 | #include <linux/mtd/nand.h> |
16 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
@@ -18,8 +19,6 @@ | |||
18 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
19 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
20 | #include <linux/gpio.h> | 21 | #include <linux/gpio.h> |
21 | #include <linux/spi/spi.h> | ||
22 | #include <linux/spi/spi_gpio.h> | ||
23 | #include <video/sh_mobile_lcdc.h> | 22 | #include <video/sh_mobile_lcdc.h> |
24 | #include <media/sh_mobile_ceu.h> | 23 | #include <media/sh_mobile_ceu.h> |
25 | #include <media/ov772x.h> | 24 | #include <media/ov772x.h> |
@@ -27,7 +26,7 @@ | |||
27 | #include <asm/clock.h> | 26 | #include <asm/clock.h> |
28 | #include <asm/machvec.h> | 27 | #include <asm/machvec.h> |
29 | #include <asm/io.h> | 28 | #include <asm/io.h> |
30 | #include <asm/sh_keysc.h> | 29 | #include <asm/suspend.h> |
31 | #include <mach/migor.h> | 30 | #include <mach/migor.h> |
32 | #include <cpu/sh7722.h> | 31 | #include <cpu/sh7722.h> |
33 | 32 | ||
@@ -390,17 +389,25 @@ static struct platform_device migor_ceu_device = { | |||
390 | }, | 389 | }, |
391 | }; | 390 | }; |
392 | 391 | ||
393 | struct spi_gpio_platform_data sdcard_cn9_platform_data = { | 392 | static struct resource sdhi_cn9_resources[] = { |
394 | .sck = GPIO_PTD0, | 393 | [0] = { |
395 | .mosi = GPIO_PTD1, | 394 | .name = "SDHI", |
396 | .miso = GPIO_PTD2, | 395 | .start = 0x04ce0000, |
397 | .num_chipselect = 1, | 396 | .end = 0x04ce01ff, |
397 | .flags = IORESOURCE_MEM, | ||
398 | }, | ||
399 | [1] = { | ||
400 | .start = 101, | ||
401 | .flags = IORESOURCE_IRQ, | ||
402 | }, | ||
398 | }; | 403 | }; |
399 | 404 | ||
400 | static struct platform_device sdcard_cn9_device = { | 405 | static struct platform_device sdhi_cn9_device = { |
401 | .name = "spi_gpio", | 406 | .name = "sh_mobile_sdhi", |
402 | .dev = { | 407 | .num_resources = ARRAY_SIZE(sdhi_cn9_resources), |
403 | .platform_data = &sdcard_cn9_platform_data, | 408 | .resource = sdhi_cn9_resources, |
409 | .archdata = { | ||
410 | .hwblk_id = HWBLK_SDHI, | ||
404 | }, | 411 | }, |
405 | }; | 412 | }; |
406 | 413 | ||
@@ -467,23 +474,24 @@ static struct platform_device *migor_devices[] __initdata = { | |||
467 | &migor_ceu_device, | 474 | &migor_ceu_device, |
468 | &migor_nor_flash_device, | 475 | &migor_nor_flash_device, |
469 | &migor_nand_flash_device, | 476 | &migor_nand_flash_device, |
470 | &sdcard_cn9_device, | 477 | &sdhi_cn9_device, |
471 | &migor_camera[0], | 478 | &migor_camera[0], |
472 | &migor_camera[1], | 479 | &migor_camera[1], |
473 | }; | 480 | }; |
474 | 481 | ||
475 | static struct spi_board_info migor_spi_devices[] = { | 482 | extern char migor_sdram_enter_start; |
476 | { | 483 | extern char migor_sdram_enter_end; |
477 | .modalias = "mmc_spi", | 484 | extern char migor_sdram_leave_start; |
478 | .max_speed_hz = 5000000, | 485 | extern char migor_sdram_leave_end; |
479 | .chip_select = 0, | ||
480 | .controller_data = (void *) GPIO_PTD5, | ||
481 | }, | ||
482 | }; | ||
483 | 486 | ||
484 | static int __init migor_devices_setup(void) | 487 | static int __init migor_devices_setup(void) |
485 | { | 488 | { |
486 | 489 | /* register board specific self-refresh code */ | |
490 | sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF, | ||
491 | &migor_sdram_enter_start, | ||
492 | &migor_sdram_enter_end, | ||
493 | &migor_sdram_leave_start, | ||
494 | &migor_sdram_leave_end); | ||
487 | #ifdef CONFIG_PM | 495 | #ifdef CONFIG_PM |
488 | /* Let D11 LED show STATUS0 */ | 496 | /* Let D11 LED show STATUS0 */ |
489 | gpio_request(GPIO_FN_STATUS0, NULL); | 497 | gpio_request(GPIO_FN_STATUS0, NULL); |
@@ -525,6 +533,16 @@ static int __init migor_devices_setup(void) | |||
525 | gpio_request(GPIO_PTA1, NULL); | 533 | gpio_request(GPIO_PTA1, NULL); |
526 | gpio_direction_input(GPIO_PTA1); | 534 | gpio_direction_input(GPIO_PTA1); |
527 | 535 | ||
536 | /* SDHI */ | ||
537 | gpio_request(GPIO_FN_SDHICD, NULL); | ||
538 | gpio_request(GPIO_FN_SDHIWP, NULL); | ||
539 | gpio_request(GPIO_FN_SDHID3, NULL); | ||
540 | gpio_request(GPIO_FN_SDHID2, NULL); | ||
541 | gpio_request(GPIO_FN_SDHID1, NULL); | ||
542 | gpio_request(GPIO_FN_SDHID0, NULL); | ||
543 | gpio_request(GPIO_FN_SDHICMD, NULL); | ||
544 | gpio_request(GPIO_FN_SDHICLK, NULL); | ||
545 | |||
528 | /* Touch Panel */ | 546 | /* Touch Panel */ |
529 | gpio_request(GPIO_FN_IRQ6, NULL); | 547 | gpio_request(GPIO_FN_IRQ6, NULL); |
530 | 548 | ||
@@ -612,9 +630,6 @@ static int __init migor_devices_setup(void) | |||
612 | i2c_register_board_info(0, migor_i2c_devices, | 630 | i2c_register_board_info(0, migor_i2c_devices, |
613 | ARRAY_SIZE(migor_i2c_devices)); | 631 | ARRAY_SIZE(migor_i2c_devices)); |
614 | 632 | ||
615 | spi_register_board_info(migor_spi_devices, | ||
616 | ARRAY_SIZE(migor_spi_devices)); | ||
617 | |||
618 | return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices)); | 633 | return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices)); |
619 | } | 634 | } |
620 | arch_initcall(migor_devices_setup); | 635 | arch_initcall(migor_devices_setup); |
diff --git a/arch/sh/boards/mach-r2d/irq.c b/arch/sh/boards/mach-r2d/irq.c index c70fecedcac4..78d7b27c80da 100644 --- a/arch/sh/boards/mach-r2d/irq.c +++ b/arch/sh/boards/mach-r2d/irq.c | |||
@@ -116,7 +116,7 @@ static unsigned char irl2irq[R2D_NR_IRL]; | |||
116 | 116 | ||
117 | int rts7751r2d_irq_demux(int irq) | 117 | int rts7751r2d_irq_demux(int irq) |
118 | { | 118 | { |
119 | if (irq >= R2D_NR_IRL || !irl2irq[irq]) | 119 | if (irq >= R2D_NR_IRL || irq < 0 || !irl2irq[irq]) |
120 | return irq; | 120 | return irq; |
121 | 121 | ||
122 | return irl2irq[irq]; | 122 | return irl2irq[irq]; |
diff --git a/arch/sh/boards/mach-se/7722/irq.c b/arch/sh/boards/mach-se/7722/irq.c index 02d21a3e2a8f..4eb31acfafef 100644 --- a/arch/sh/boards/mach-se/7722/irq.c +++ b/arch/sh/boards/mach-se/7722/irq.c | |||
@@ -16,15 +16,17 @@ | |||
16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
17 | #include <mach-se/mach/se7722.h> | 17 | #include <mach-se/mach/se7722.h> |
18 | 18 | ||
19 | unsigned int se7722_fpga_irq[SE7722_FPGA_IRQ_NR] = { 0, }; | ||
20 | |||
19 | static void disable_se7722_irq(unsigned int irq) | 21 | static void disable_se7722_irq(unsigned int irq) |
20 | { | 22 | { |
21 | unsigned int bit = irq - SE7722_FPGA_IRQ_BASE; | 23 | unsigned int bit = (unsigned int)get_irq_chip_data(irq); |
22 | ctrl_outw(ctrl_inw(IRQ01_MASK) | 1 << bit, IRQ01_MASK); | 24 | ctrl_outw(ctrl_inw(IRQ01_MASK) | 1 << bit, IRQ01_MASK); |
23 | } | 25 | } |
24 | 26 | ||
25 | static void enable_se7722_irq(unsigned int irq) | 27 | static void enable_se7722_irq(unsigned int irq) |
26 | { | 28 | { |
27 | unsigned int bit = irq - SE7722_FPGA_IRQ_BASE; | 29 | unsigned int bit = (unsigned int)get_irq_chip_data(irq); |
28 | ctrl_outw(ctrl_inw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK); | 30 | ctrl_outw(ctrl_inw(IRQ01_MASK) & ~(1 << bit), IRQ01_MASK); |
29 | } | 31 | } |
30 | 32 | ||
@@ -38,18 +40,15 @@ static struct irq_chip se7722_irq_chip __read_mostly = { | |||
38 | static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc) | 40 | static void se7722_irq_demux(unsigned int irq, struct irq_desc *desc) |
39 | { | 41 | { |
40 | unsigned short intv = ctrl_inw(IRQ01_STS); | 42 | unsigned short intv = ctrl_inw(IRQ01_STS); |
41 | struct irq_desc *ext_desc; | 43 | unsigned int ext_irq = 0; |
42 | unsigned int ext_irq = SE7722_FPGA_IRQ_BASE; | ||
43 | 44 | ||
44 | intv &= (1 << SE7722_FPGA_IRQ_NR) - 1; | 45 | intv &= (1 << SE7722_FPGA_IRQ_NR) - 1; |
45 | 46 | ||
46 | while (intv) { | 47 | for (; intv; intv >>= 1, ext_irq++) { |
47 | if (intv & 1) { | 48 | if (!(intv & 1)) |
48 | ext_desc = irq_desc + ext_irq; | 49 | continue; |
49 | handle_level_irq(ext_irq, ext_desc); | 50 | |
50 | } | 51 | generic_handle_irq(se7722_fpga_irq[ext_irq]); |
51 | intv >>= 1; | ||
52 | ext_irq++; | ||
53 | } | 52 | } |
54 | } | 53 | } |
55 | 54 | ||
@@ -63,11 +62,18 @@ void __init init_se7722_IRQ(void) | |||
63 | ctrl_outw(0, IRQ01_MASK); /* disable all irqs */ | 62 | ctrl_outw(0, IRQ01_MASK); /* disable all irqs */ |
64 | ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */ | 63 | ctrl_outw(0x2000, 0xb03fffec); /* mrshpc irq enable */ |
65 | 64 | ||
66 | for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) | 65 | for (i = 0; i < SE7722_FPGA_IRQ_NR; i++) { |
67 | set_irq_chip_and_handler_name(SE7722_FPGA_IRQ_BASE + i, | 66 | se7722_fpga_irq[i] = create_irq(); |
67 | if (se7722_fpga_irq[i] < 0) | ||
68 | return; | ||
69 | |||
70 | set_irq_chip_and_handler_name(se7722_fpga_irq[i], | ||
68 | &se7722_irq_chip, | 71 | &se7722_irq_chip, |
69 | handle_level_irq, "level"); | 72 | handle_level_irq, "level"); |
70 | 73 | ||
74 | set_irq_chip_data(se7722_fpga_irq[i], (void *)i); | ||
75 | } | ||
76 | |||
71 | set_irq_chained_handler(IRQ0_IRQ, se7722_irq_demux); | 77 | set_irq_chained_handler(IRQ0_IRQ, se7722_irq_demux); |
72 | set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW); | 78 | set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW); |
73 | 79 | ||
diff --git a/arch/sh/boards/mach-se/7722/setup.c b/arch/sh/boards/mach-se/7722/setup.c index 36374078e521..b1cb9425b600 100644 --- a/arch/sh/boards/mach-se/7722/setup.c +++ b/arch/sh/boards/mach-se/7722/setup.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/ata_platform.h> | 15 | #include <linux/ata_platform.h> |
16 | #include <linux/input.h> | 16 | #include <linux/input.h> |
17 | #include <linux/input/sh_keysc.h> | ||
17 | #include <linux/smc91x.h> | 18 | #include <linux/smc91x.h> |
18 | #include <mach-se/mach/se7722.h> | 19 | #include <mach-se/mach/se7722.h> |
19 | #include <mach-se/mach/mrshpc.h> | 20 | #include <mach-se/mach/mrshpc.h> |
@@ -21,7 +22,6 @@ | |||
21 | #include <asm/clock.h> | 22 | #include <asm/clock.h> |
22 | #include <asm/io.h> | 23 | #include <asm/io.h> |
23 | #include <asm/heartbeat.h> | 24 | #include <asm/heartbeat.h> |
24 | #include <asm/sh_keysc.h> | ||
25 | #include <cpu/sh7722.h> | 25 | #include <cpu/sh7722.h> |
26 | 26 | ||
27 | /* Heartbeat */ | 27 | /* Heartbeat */ |
@@ -60,8 +60,7 @@ static struct resource smc91x_eth_resources[] = { | |||
60 | .flags = IORESOURCE_MEM, | 60 | .flags = IORESOURCE_MEM, |
61 | }, | 61 | }, |
62 | [1] = { | 62 | [1] = { |
63 | .start = SMC_IRQ, | 63 | /* Filled in later */ |
64 | .end = SMC_IRQ, | ||
65 | .flags = IORESOURCE_IRQ, | 64 | .flags = IORESOURCE_IRQ, |
66 | }, | 65 | }, |
67 | }; | 66 | }; |
@@ -90,8 +89,7 @@ static struct resource cf_ide_resources[] = { | |||
90 | .flags = IORESOURCE_IO, | 89 | .flags = IORESOURCE_IO, |
91 | }, | 90 | }, |
92 | [2] = { | 91 | [2] = { |
93 | .start = MRSHPC_IRQ0, | 92 | /* Filled in later */ |
94 | .end = MRSHPC_IRQ0, | ||
95 | .flags = IORESOURCE_IRQ, | 93 | .flags = IORESOURCE_IRQ, |
96 | }, | 94 | }, |
97 | }; | 95 | }; |
@@ -153,6 +151,14 @@ static struct platform_device *se7722_devices[] __initdata = { | |||
153 | static int __init se7722_devices_setup(void) | 151 | static int __init se7722_devices_setup(void) |
154 | { | 152 | { |
155 | mrshpc_setup_windows(); | 153 | mrshpc_setup_windows(); |
154 | |||
155 | /* Wire-up dynamic vectors */ | ||
156 | cf_ide_resources[2].start = cf_ide_resources[2].end = | ||
157 | se7722_fpga_irq[SE7722_FPGA_IRQ_MRSHPC0]; | ||
158 | |||
159 | smc91x_eth_resources[1].start = smc91x_eth_resources[1].end = | ||
160 | se7722_fpga_irq[SE7722_FPGA_IRQ_SMC]; | ||
161 | |||
156 | return platform_add_devices(se7722_devices, ARRAY_SIZE(se7722_devices)); | 162 | return platform_add_devices(se7722_devices, ARRAY_SIZE(se7722_devices)); |
157 | } | 163 | } |
158 | device_initcall(se7722_devices_setup); | 164 | device_initcall(se7722_devices_setup); |
@@ -193,6 +199,5 @@ static void __init se7722_setup(char **cmdline_p) | |||
193 | static struct sh_machine_vector mv_se7722 __initmv = { | 199 | static struct sh_machine_vector mv_se7722 __initmv = { |
194 | .mv_name = "Solution Engine 7722" , | 200 | .mv_name = "Solution Engine 7722" , |
195 | .mv_setup = se7722_setup , | 201 | .mv_setup = se7722_setup , |
196 | .mv_nr_irqs = SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_NR, | ||
197 | .mv_init_irq = init_se7722_IRQ, | 202 | .mv_init_irq = init_se7722_IRQ, |
198 | }; | 203 | }; |
diff --git a/arch/sh/boards/mach-se/7724/Makefile b/arch/sh/boards/mach-se/7724/Makefile index 349cbd6ce82d..a08b36830f0e 100644 --- a/arch/sh/boards/mach-se/7724/Makefile +++ b/arch/sh/boards/mach-se/7724/Makefile | |||
@@ -7,4 +7,4 @@ | |||
7 | # | 7 | # |
8 | # | 8 | # |
9 | 9 | ||
10 | obj-y := setup.o irq.o \ No newline at end of file | 10 | obj-y := setup.o irq.o sdram.o |
diff --git a/arch/sh/boards/mach-se/7724/sdram.S b/arch/sh/boards/mach-se/7724/sdram.S new file mode 100644 index 000000000000..9040167d5022 --- /dev/null +++ b/arch/sh/boards/mach-se/7724/sdram.S | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * MS7724SE sdram self/auto-refresh setup code | ||
3 | * | ||
4 | * Copyright (C) 2009 Magnus Damm | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/sys.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/asm-offsets.h> | ||
15 | #include <asm/suspend.h> | ||
16 | #include <asm/romimage-macros.h> | ||
17 | |||
18 | /* code to enter and leave self-refresh. must be self-contained. | ||
19 | * this code will be copied to on-chip memory and executed from there. | ||
20 | */ | ||
21 | .balign 4 | ||
22 | ENTRY(ms7724se_sdram_enter_start) | ||
23 | |||
24 | /* DBSC: put memory in self-refresh mode */ | ||
25 | |||
26 | ED 0xFD000010, 0x00000000 /* DBEN */ | ||
27 | ED 0xFD000040, 0x00000000 /* DBRFPDN0 */ | ||
28 | ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */ | ||
29 | ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */ | ||
30 | ED 0xFD000040, 0x00000001 /* DBRFPDN0 */ | ||
31 | |||
32 | rts | ||
33 | nop | ||
34 | |||
35 | ENTRY(ms7724se_sdram_enter_end) | ||
36 | |||
37 | .balign 4 | ||
38 | ENTRY(ms7724se_sdram_leave_start) | ||
39 | |||
40 | /* DBSC: put memory in auto-refresh mode */ | ||
41 | |||
42 | ED 0xFD000040, 0x00000000 /* DBRFPDN0 */ | ||
43 | WAIT 1 | ||
44 | ED 0xFD000014, 0x00000002 /* DBCMDCNT (PALL) */ | ||
45 | ED 0xFD000014, 0x00000004 /* DBCMDCNT (REF) */ | ||
46 | ED 0xFD000010, 0x00000001 /* DBEN */ | ||
47 | ED 0xFD000040, 0x00010000 /* DBRFPDN0 */ | ||
48 | |||
49 | rts | ||
50 | nop | ||
51 | |||
52 | ENTRY(ms7724se_sdram_leave_end) | ||
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 0894bba9fade..4b0f0c0dc2b8 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/smc91x.h> | 19 | #include <linux/smc91x.h> |
20 | #include <linux/gpio.h> | 20 | #include <linux/gpio.h> |
21 | #include <linux/input.h> | 21 | #include <linux/input.h> |
22 | #include <linux/input/sh_keysc.h> | ||
22 | #include <linux/usb/r8a66597.h> | 23 | #include <linux/usb/r8a66597.h> |
23 | #include <video/sh_mobile_lcdc.h> | 24 | #include <video/sh_mobile_lcdc.h> |
24 | #include <media/sh_mobile_ceu.h> | 25 | #include <media/sh_mobile_ceu.h> |
@@ -27,7 +28,7 @@ | |||
27 | #include <asm/heartbeat.h> | 28 | #include <asm/heartbeat.h> |
28 | #include <asm/sh_eth.h> | 29 | #include <asm/sh_eth.h> |
29 | #include <asm/clock.h> | 30 | #include <asm/clock.h> |
30 | #include <asm/sh_keysc.h> | 31 | #include <asm/suspend.h> |
31 | #include <cpu/sh7724.h> | 32 | #include <cpu/sh7724.h> |
32 | #include <mach-se/mach/se7724.h> | 33 | #include <mach-se/mach/se7724.h> |
33 | 34 | ||
@@ -451,6 +452,52 @@ static struct platform_device sh7724_usb1_gadget_device = { | |||
451 | .resource = sh7724_usb1_gadget_resources, | 452 | .resource = sh7724_usb1_gadget_resources, |
452 | }; | 453 | }; |
453 | 454 | ||
455 | static struct resource sdhi0_cn7_resources[] = { | ||
456 | [0] = { | ||
457 | .name = "SDHI0", | ||
458 | .start = 0x04ce0000, | ||
459 | .end = 0x04ce01ff, | ||
460 | .flags = IORESOURCE_MEM, | ||
461 | }, | ||
462 | [1] = { | ||
463 | .start = 101, | ||
464 | .flags = IORESOURCE_IRQ, | ||
465 | }, | ||
466 | }; | ||
467 | |||
468 | static struct platform_device sdhi0_cn7_device = { | ||
469 | .name = "sh_mobile_sdhi", | ||
470 | .id = 0, | ||
471 | .num_resources = ARRAY_SIZE(sdhi0_cn7_resources), | ||
472 | .resource = sdhi0_cn7_resources, | ||
473 | .archdata = { | ||
474 | .hwblk_id = HWBLK_SDHI0, | ||
475 | }, | ||
476 | }; | ||
477 | |||
478 | static struct resource sdhi1_cn8_resources[] = { | ||
479 | [0] = { | ||
480 | .name = "SDHI1", | ||
481 | .start = 0x04cf0000, | ||
482 | .end = 0x04cf01ff, | ||
483 | .flags = IORESOURCE_MEM, | ||
484 | }, | ||
485 | [1] = { | ||
486 | .start = 24, | ||
487 | .flags = IORESOURCE_IRQ, | ||
488 | }, | ||
489 | }; | ||
490 | |||
491 | static struct platform_device sdhi1_cn8_device = { | ||
492 | .name = "sh_mobile_sdhi", | ||
493 | .id = 1, | ||
494 | .num_resources = ARRAY_SIZE(sdhi1_cn8_resources), | ||
495 | .resource = sdhi1_cn8_resources, | ||
496 | .archdata = { | ||
497 | .hwblk_id = HWBLK_SDHI1, | ||
498 | }, | ||
499 | }; | ||
500 | |||
454 | static struct platform_device *ms7724se_devices[] __initdata = { | 501 | static struct platform_device *ms7724se_devices[] __initdata = { |
455 | &heartbeat_device, | 502 | &heartbeat_device, |
456 | &smc91x_eth_device, | 503 | &smc91x_eth_device, |
@@ -463,6 +510,8 @@ static struct platform_device *ms7724se_devices[] __initdata = { | |||
463 | &sh7724_usb0_host_device, | 510 | &sh7724_usb0_host_device, |
464 | &sh7724_usb1_gadget_device, | 511 | &sh7724_usb1_gadget_device, |
465 | &fsi_device, | 512 | &fsi_device, |
513 | &sdhi0_cn7_device, | ||
514 | &sdhi1_cn8_device, | ||
466 | }; | 515 | }; |
467 | 516 | ||
468 | #define EEPROM_OP 0xBA206000 | 517 | #define EEPROM_OP 0xBA206000 |
@@ -487,7 +536,7 @@ static int __init sh_eth_is_eeprom_ready(void) | |||
487 | static void __init sh_eth_init(void) | 536 | static void __init sh_eth_init(void) |
488 | { | 537 | { |
489 | int i; | 538 | int i; |
490 | u16 mac[3]; | 539 | u16 mac; |
491 | 540 | ||
492 | /* check EEPROM status */ | 541 | /* check EEPROM status */ |
493 | if (!sh_eth_is_eeprom_ready()) | 542 | if (!sh_eth_is_eeprom_ready()) |
@@ -501,16 +550,10 @@ static void __init sh_eth_init(void) | |||
501 | if (!sh_eth_is_eeprom_ready()) | 550 | if (!sh_eth_is_eeprom_ready()) |
502 | return; | 551 | return; |
503 | 552 | ||
504 | mac[i] = ctrl_inw(EEPROM_DATA); | 553 | mac = ctrl_inw(EEPROM_DATA); |
505 | mac[i] = ((mac[i] & 0xFF) << 8) | (mac[i] >> 8); /* swap */ | 554 | sh_eth_plat.mac_addr[i << 1] = mac & 0xff; |
555 | sh_eth_plat.mac_addr[(i << 1) + 1] = mac >> 8; | ||
506 | } | 556 | } |
507 | |||
508 | /* reset sh-eth */ | ||
509 | ctrl_outl(0x1, SH_ETH_ADDR + 0x0); | ||
510 | |||
511 | /* set MAC addr */ | ||
512 | ctrl_outl(((mac[0] << 16) | (mac[1])), SH_ETH_MAHR); | ||
513 | ctrl_outl((mac[2]), SH_ETH_MALR); | ||
514 | } | 557 | } |
515 | 558 | ||
516 | #define SW4140 0xBA201000 | 559 | #define SW4140 0xBA201000 |
@@ -527,11 +570,22 @@ static void __init sh_eth_init(void) | |||
527 | #define SW41_G 0x4000 | 570 | #define SW41_G 0x4000 |
528 | #define SW41_H 0x8000 | 571 | #define SW41_H 0x8000 |
529 | 572 | ||
573 | extern char ms7724se_sdram_enter_start; | ||
574 | extern char ms7724se_sdram_enter_end; | ||
575 | extern char ms7724se_sdram_leave_start; | ||
576 | extern char ms7724se_sdram_leave_end; | ||
577 | |||
530 | static int __init devices_setup(void) | 578 | static int __init devices_setup(void) |
531 | { | 579 | { |
532 | u16 sw = ctrl_inw(SW4140); /* select camera, monitor */ | 580 | u16 sw = ctrl_inw(SW4140); /* select camera, monitor */ |
533 | struct clk *fsia_clk; | 581 | struct clk *fsia_clk; |
534 | 582 | ||
583 | /* register board specific self-refresh code */ | ||
584 | sh_mobile_register_self_refresh(SUSP_SH_STANDBY | SUSP_SH_SF, | ||
585 | &ms7724se_sdram_enter_start, | ||
586 | &ms7724se_sdram_enter_end, | ||
587 | &ms7724se_sdram_leave_start, | ||
588 | &ms7724se_sdram_leave_end); | ||
535 | /* Reset Release */ | 589 | /* Reset Release */ |
536 | ctrl_outw(ctrl_inw(FPGA_OUT) & | 590 | ctrl_outw(ctrl_inw(FPGA_OUT) & |
537 | ~((1 << 1) | /* LAN */ | 591 | ~((1 << 1) | /* LAN */ |
@@ -701,6 +755,26 @@ static int __init devices_setup(void) | |||
701 | clk_set_rate(&fsimcka_clk, 11000); | 755 | clk_set_rate(&fsimcka_clk, 11000); |
702 | clk_put(fsia_clk); | 756 | clk_put(fsia_clk); |
703 | 757 | ||
758 | /* SDHI0 connected to cn7 */ | ||
759 | gpio_request(GPIO_FN_SDHI0CD, NULL); | ||
760 | gpio_request(GPIO_FN_SDHI0WP, NULL); | ||
761 | gpio_request(GPIO_FN_SDHI0D3, NULL); | ||
762 | gpio_request(GPIO_FN_SDHI0D2, NULL); | ||
763 | gpio_request(GPIO_FN_SDHI0D1, NULL); | ||
764 | gpio_request(GPIO_FN_SDHI0D0, NULL); | ||
765 | gpio_request(GPIO_FN_SDHI0CMD, NULL); | ||
766 | gpio_request(GPIO_FN_SDHI0CLK, NULL); | ||
767 | |||
768 | /* SDHI1 connected to cn8 */ | ||
769 | gpio_request(GPIO_FN_SDHI1CD, NULL); | ||
770 | gpio_request(GPIO_FN_SDHI1WP, NULL); | ||
771 | gpio_request(GPIO_FN_SDHI1D3, NULL); | ||
772 | gpio_request(GPIO_FN_SDHI1D2, NULL); | ||
773 | gpio_request(GPIO_FN_SDHI1D1, NULL); | ||
774 | gpio_request(GPIO_FN_SDHI1D0, NULL); | ||
775 | gpio_request(GPIO_FN_SDHI1CMD, NULL); | ||
776 | gpio_request(GPIO_FN_SDHI1CLK, NULL); | ||
777 | |||
704 | /* | 778 | /* |
705 | * enable SH-Eth | 779 | * enable SH-Eth |
706 | * | 780 | * |
diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c index fd56a71ca9d9..b51b1fc4baae 100644 --- a/arch/sh/boot/compressed/misc.c +++ b/arch/sh/boot/compressed/misc.c | |||
@@ -131,7 +131,7 @@ void decompress_kernel(void) | |||
131 | #ifdef CONFIG_SUPERH64 | 131 | #ifdef CONFIG_SUPERH64 |
132 | output_addr = (CONFIG_MEMORY_START + 0x2000); | 132 | output_addr = (CONFIG_MEMORY_START + 0x2000); |
133 | #else | 133 | #else |
134 | output_addr = PHYSADDR((unsigned long)&_text+PAGE_SIZE); | 134 | output_addr = __pa((unsigned long)&_text+PAGE_SIZE); |
135 | #ifdef CONFIG_29BIT | 135 | #ifdef CONFIG_29BIT |
136 | output_addr |= P2SEG; | 136 | output_addr |= P2SEG; |
137 | #endif | 137 | #endif |
diff --git a/arch/sh/boot/romimage/Makefile b/arch/sh/boot/romimage/Makefile index 5806eee84f6f..f473a24a2d92 100644 --- a/arch/sh/boot/romimage/Makefile +++ b/arch/sh/boot/romimage/Makefile | |||
@@ -4,16 +4,22 @@ | |||
4 | # create an image suitable for burning to flash from zImage | 4 | # create an image suitable for burning to flash from zImage |
5 | # | 5 | # |
6 | 6 | ||
7 | targets := vmlinux head.o | 7 | targets := vmlinux head.o zeropage.bin piggy.o |
8 | 8 | ||
9 | OBJECTS = $(obj)/head.o | 9 | OBJECTS = $(obj)/head.o |
10 | LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext 0 -e romstart | 10 | LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext 0 -e romstart \ |
11 | -T $(obj)/../../kernel/vmlinux.lds | ||
11 | 12 | ||
12 | $(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE | 13 | $(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE |
13 | $(call if_changed,ld) | 14 | $(call if_changed,ld) |
14 | @: | 15 | @: |
15 | 16 | ||
17 | OBJCOPYFLAGS += -j .empty_zero_page | ||
18 | |||
19 | $(obj)/zeropage.bin: vmlinux FORCE | ||
20 | $(call if_changed,objcopy) | ||
21 | |||
16 | LDFLAGS_piggy.o := -r --format binary --oformat $(ld-bfd) -T | 22 | LDFLAGS_piggy.o := -r --format binary --oformat $(ld-bfd) -T |
17 | 23 | ||
18 | $(obj)/piggy.o: $(obj)/vmlinux.scr arch/sh/boot/zImage FORCE | 24 | $(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/zeropage.bin arch/sh/boot/zImage FORCE |
19 | $(call if_changed,ld) | 25 | $(call if_changed,ld) |
diff --git a/arch/sh/boot/romimage/head.S b/arch/sh/boot/romimage/head.S index 219bc626dd71..93e779a405ec 100644 --- a/arch/sh/boot/romimage/head.S +++ b/arch/sh/boot/romimage/head.S | |||
@@ -5,6 +5,44 @@ | |||
5 | */ | 5 | */ |
6 | 6 | ||
7 | .text | 7 | .text |
8 | #include <asm/page.h> | ||
9 | |||
8 | .global romstart | 10 | .global romstart |
9 | romstart: | 11 | romstart: |
12 | /* include board specific setup code */ | ||
10 | #include <mach/romimage.h> | 13 | #include <mach/romimage.h> |
14 | |||
15 | /* copy the empty_zero_page contents to where vmlinux expects it */ | ||
16 | mova empty_zero_page_src, r0 | ||
17 | mov.l empty_zero_page_dst, r1 | ||
18 | mov #(PAGE_SHIFT - 4), r4 | ||
19 | mov #1, r3 | ||
20 | shld r4, r3 /* r3 = PAGE_SIZE / 16 */ | ||
21 | |||
22 | 1: | ||
23 | mov.l @r0, r4 | ||
24 | mov.l @(4, r0), r5 | ||
25 | mov.l @(8, r0), r6 | ||
26 | mov.l @(12, r0), r7 | ||
27 | add #16,r0 | ||
28 | mov.l r4, @r1 | ||
29 | mov.l r5, @(4, r1) | ||
30 | mov.l r6, @(8, r1) | ||
31 | mov.l r7, @(12, r1) | ||
32 | dt r3 | ||
33 | add #16,r1 | ||
34 | bf 1b | ||
35 | |||
36 | /* jump to the zImage entry point located after the zero page data */ | ||
37 | mov #PAGE_SHIFT, r4 | ||
38 | mov #1, r1 | ||
39 | shld r4, r1 | ||
40 | mova empty_zero_page_src, r0 | ||
41 | add r1, r0 | ||
42 | jmp @r0 | ||
43 | nop | ||
44 | |||
45 | .align 2 | ||
46 | empty_zero_page_dst: | ||
47 | .long _text | ||
48 | empty_zero_page_src: | ||
diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c index 347ee11351ec..1ee631d3725e 100644 --- a/arch/sh/drivers/dma/dma-sysfs.c +++ b/arch/sh/drivers/dma/dma-sysfs.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/init.h> | 13 | #include <linux/init.h> |
14 | #include <linux/sysdev.h> | 14 | #include <linux/sysdev.h> |
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/module.h> | ||
17 | #include <linux/err.h> | 16 | #include <linux/err.h> |
18 | #include <linux/string.h> | 17 | #include <linux/string.h> |
19 | #include <asm/dma.h> | 18 | #include <asm/dma.h> |
@@ -21,7 +20,6 @@ | |||
21 | static struct sysdev_class dma_sysclass = { | 20 | static struct sysdev_class dma_sysclass = { |
22 | .name = "dma", | 21 | .name = "dma", |
23 | }; | 22 | }; |
24 | EXPORT_SYMBOL(dma_sysclass); | ||
25 | 23 | ||
26 | static ssize_t dma_show_devices(struct sys_device *dev, | 24 | static ssize_t dma_show_devices(struct sys_device *dev, |
27 | struct sysdev_attribute *attr, char *buf) | 25 | struct sysdev_attribute *attr, char *buf) |
diff --git a/arch/sh/drivers/pci/Kconfig b/arch/sh/drivers/pci/Kconfig deleted file mode 100644 index e8db585a6638..000000000000 --- a/arch/sh/drivers/pci/Kconfig +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | config PCI | ||
2 | bool "PCI support" | ||
3 | depends on SYS_SUPPORTS_PCI | ||
4 | help | ||
5 | Find out whether you have a PCI motherboard. PCI is the name of a | ||
6 | bus system, i.e. the way the CPU talks to the other stuff inside | ||
7 | your box. If you have PCI, say Y, otherwise N. | ||
8 | |||
9 | config SH_PCIDMA_NONCOHERENT | ||
10 | bool "Cache and PCI noncoherent" | ||
11 | depends on PCI | ||
12 | default y | ||
13 | help | ||
14 | Enable this option if your platform does not have a CPU cache which | ||
15 | remains coherent with PCI DMA. It is safest to say 'Y', although you | ||
16 | will see better performance if you can say 'N', because the PCI DMA | ||
17 | code will not have to flush the CPU's caches. If you have a PCI host | ||
18 | bridge integrated with your SH CPU, refer carefully to the chip specs | ||
19 | to see if you can say 'N' here. Otherwise, leave it as 'Y'. | ||
diff --git a/arch/sh/include/asm/addrspace.h b/arch/sh/include/asm/addrspace.h index 80d40813e057..99d6b3ecbe22 100644 --- a/arch/sh/include/asm/addrspace.h +++ b/arch/sh/include/asm/addrspace.h | |||
@@ -28,9 +28,6 @@ | |||
28 | /* Returns the privileged segment base of a given address */ | 28 | /* Returns the privileged segment base of a given address */ |
29 | #define PXSEG(a) (((unsigned long)(a)) & 0xe0000000) | 29 | #define PXSEG(a) (((unsigned long)(a)) & 0xe0000000) |
30 | 30 | ||
31 | /* Returns the physical address of a PnSEG (n=1,2) address */ | ||
32 | #define PHYSADDR(a) (((unsigned long)(a)) & 0x1fffffff) | ||
33 | |||
34 | #if defined(CONFIG_29BIT) || defined(CONFIG_PMB_FIXED) | 31 | #if defined(CONFIG_29BIT) || defined(CONFIG_PMB_FIXED) |
35 | /* | 32 | /* |
36 | * Map an address to a certain privileged segment | 33 | * Map an address to a certain privileged segment |
@@ -60,5 +57,11 @@ | |||
60 | #define P3_ADDR_MAX P4SEG | 57 | #define P3_ADDR_MAX P4SEG |
61 | #endif | 58 | #endif |
62 | 59 | ||
60 | #ifndef __ASSEMBLY__ | ||
61 | #ifdef CONFIG_PMB | ||
62 | extern int __in_29bit_mode(void); | ||
63 | #endif /* CONFIG_PMB */ | ||
64 | #endif /* __ASSEMBLY__ */ | ||
65 | |||
63 | #endif /* __KERNEL__ */ | 66 | #endif /* __KERNEL__ */ |
64 | #endif /* __ASM_SH_ADDRSPACE_H */ | 67 | #endif /* __ASM_SH_ADDRSPACE_H */ |
diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index e8e78137c6f5..b16388d71954 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h | |||
@@ -78,11 +78,10 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) | |||
78 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) | 78 | #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) |
79 | #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) | 79 | #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) |
80 | 80 | ||
81 | /* Atomic operations are already serializing on SH */ | 81 | #define smp_mb__before_atomic_dec() smp_mb() |
82 | #define smp_mb__before_atomic_dec() barrier() | 82 | #define smp_mb__after_atomic_dec() smp_mb() |
83 | #define smp_mb__after_atomic_dec() barrier() | 83 | #define smp_mb__before_atomic_inc() smp_mb() |
84 | #define smp_mb__before_atomic_inc() barrier() | 84 | #define smp_mb__after_atomic_inc() smp_mb() |
85 | #define smp_mb__after_atomic_inc() barrier() | ||
86 | 85 | ||
87 | #include <asm-generic/atomic-long.h> | 86 | #include <asm-generic/atomic-long.h> |
88 | #include <asm-generic/atomic64.h> | 87 | #include <asm-generic/atomic64.h> |
diff --git a/arch/sh/include/asm/bitops.h b/arch/sh/include/asm/bitops.h index ebe595b7ab1f..98511e4d28cb 100644 --- a/arch/sh/include/asm/bitops.h +++ b/arch/sh/include/asm/bitops.h | |||
@@ -26,8 +26,8 @@ | |||
26 | /* | 26 | /* |
27 | * clear_bit() doesn't provide any barrier for the compiler. | 27 | * clear_bit() doesn't provide any barrier for the compiler. |
28 | */ | 28 | */ |
29 | #define smp_mb__before_clear_bit() barrier() | 29 | #define smp_mb__before_clear_bit() smp_mb() |
30 | #define smp_mb__after_clear_bit() barrier() | 30 | #define smp_mb__after_clear_bit() smp_mb() |
31 | 31 | ||
32 | #ifdef CONFIG_SUPERH32 | 32 | #ifdef CONFIG_SUPERH32 |
33 | static inline unsigned long ffz(unsigned long word) | 33 | static inline unsigned long ffz(unsigned long word) |
diff --git a/arch/sh/include/asm/bugs.h b/arch/sh/include/asm/bugs.h index 46260fcbdf4b..02a19a1c033a 100644 --- a/arch/sh/include/asm/bugs.h +++ b/arch/sh/include/asm/bugs.h | |||
@@ -14,11 +14,15 @@ | |||
14 | 14 | ||
15 | #include <asm/processor.h> | 15 | #include <asm/processor.h> |
16 | 16 | ||
17 | extern void select_idle_routine(void); | ||
18 | |||
17 | static void __init check_bugs(void) | 19 | static void __init check_bugs(void) |
18 | { | 20 | { |
19 | extern unsigned long loops_per_jiffy; | 21 | extern unsigned long loops_per_jiffy; |
20 | char *p = &init_utsname()->machine[2]; /* "sh" */ | 22 | char *p = &init_utsname()->machine[2]; /* "sh" */ |
21 | 23 | ||
24 | select_idle_routine(); | ||
25 | |||
22 | current_cpu_data.loops_per_jiffy = loops_per_jiffy; | 26 | current_cpu_data.loops_per_jiffy = loops_per_jiffy; |
23 | 27 | ||
24 | switch (current_cpu_data.family) { | 28 | switch (current_cpu_data.family) { |
diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 69d56dd4c968..87ced133a363 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h | |||
@@ -1,219 +1,108 @@ | |||
1 | #ifndef __ASM_SH_DMA_MAPPING_H | 1 | #ifndef __ASM_SH_DMA_MAPPING_H |
2 | #define __ASM_SH_DMA_MAPPING_H | 2 | #define __ASM_SH_DMA_MAPPING_H |
3 | 3 | ||
4 | #include <linux/mm.h> | 4 | extern struct dma_map_ops *dma_ops; |
5 | #include <linux/scatterlist.h> | 5 | extern void no_iommu_init(void); |
6 | #include <linux/dma-debug.h> | 6 | |
7 | #include <asm/cacheflush.h> | 7 | static inline struct dma_map_ops *get_dma_ops(struct device *dev) |
8 | #include <asm/io.h> | 8 | { |
9 | return dma_ops; | ||
10 | } | ||
11 | |||
9 | #include <asm-generic/dma-coherent.h> | 12 | #include <asm-generic/dma-coherent.h> |
13 | #include <asm-generic/dma-mapping-common.h> | ||
14 | |||
15 | static inline int dma_supported(struct device *dev, u64 mask) | ||
16 | { | ||
17 | struct dma_map_ops *ops = get_dma_ops(dev); | ||
10 | 18 | ||
11 | extern struct bus_type pci_bus_type; | 19 | if (ops->dma_supported) |
20 | return ops->dma_supported(dev, mask); | ||
12 | 21 | ||
13 | #define dma_supported(dev, mask) (1) | 22 | return 1; |
23 | } | ||
14 | 24 | ||
15 | static inline int dma_set_mask(struct device *dev, u64 mask) | 25 | static inline int dma_set_mask(struct device *dev, u64 mask) |
16 | { | 26 | { |
27 | struct dma_map_ops *ops = get_dma_ops(dev); | ||
28 | |||
17 | if (!dev->dma_mask || !dma_supported(dev, mask)) | 29 | if (!dev->dma_mask || !dma_supported(dev, mask)) |
18 | return -EIO; | 30 | return -EIO; |
31 | if (ops->set_dma_mask) | ||
32 | return ops->set_dma_mask(dev, mask); | ||
19 | 33 | ||
20 | *dev->dma_mask = mask; | 34 | *dev->dma_mask = mask; |
21 | 35 | ||
22 | return 0; | 36 | return 0; |
23 | } | 37 | } |
24 | 38 | ||
25 | void *dma_alloc_coherent(struct device *dev, size_t size, | ||
26 | dma_addr_t *dma_handle, gfp_t flag); | ||
27 | |||
28 | void dma_free_coherent(struct device *dev, size_t size, | ||
29 | void *vaddr, dma_addr_t dma_handle); | ||
30 | |||
31 | void dma_cache_sync(struct device *dev, void *vaddr, size_t size, | 39 | void dma_cache_sync(struct device *dev, void *vaddr, size_t size, |
32 | enum dma_data_direction dir); | 40 | enum dma_data_direction dir); |
33 | 41 | ||
34 | #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) | 42 | #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) |
35 | #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) | 43 | #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) |
36 | #define dma_is_consistent(d, h) (1) | ||
37 | |||
38 | static inline dma_addr_t dma_map_single(struct device *dev, | ||
39 | void *ptr, size_t size, | ||
40 | enum dma_data_direction dir) | ||
41 | { | ||
42 | dma_addr_t addr = virt_to_phys(ptr); | ||
43 | |||
44 | #if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT) | ||
45 | if (dev->bus == &pci_bus_type) | ||
46 | return addr; | ||
47 | #endif | ||
48 | dma_cache_sync(dev, ptr, size, dir); | ||
49 | |||
50 | debug_dma_map_page(dev, virt_to_page(ptr), | ||
51 | (unsigned long)ptr & ~PAGE_MASK, size, | ||
52 | dir, addr, true); | ||
53 | |||
54 | return addr; | ||
55 | } | ||
56 | |||
57 | static inline void dma_unmap_single(struct device *dev, dma_addr_t addr, | ||
58 | size_t size, enum dma_data_direction dir) | ||
59 | { | ||
60 | debug_dma_unmap_page(dev, addr, size, dir, true); | ||
61 | } | ||
62 | 44 | ||
63 | static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, | 45 | #ifdef CONFIG_DMA_COHERENT |
64 | int nents, enum dma_data_direction dir) | 46 | #define dma_is_consistent(d, h) (1) |
65 | { | 47 | #else |
66 | int i; | 48 | #define dma_is_consistent(d, h) (0) |
67 | |||
68 | for (i = 0; i < nents; i++) { | ||
69 | #if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT) | ||
70 | dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir); | ||
71 | #endif | 49 | #endif |
72 | sg[i].dma_address = sg_phys(&sg[i]); | ||
73 | sg[i].dma_length = sg[i].length; | ||
74 | } | ||
75 | 50 | ||
76 | debug_dma_map_sg(dev, sg, nents, i, dir); | 51 | static inline int dma_get_cache_alignment(void) |
77 | |||
78 | return nents; | ||
79 | } | ||
80 | |||
81 | static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, | ||
82 | int nents, enum dma_data_direction dir) | ||
83 | { | ||
84 | debug_dma_unmap_sg(dev, sg, nents, dir); | ||
85 | } | ||
86 | |||
87 | static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, | ||
88 | unsigned long offset, size_t size, | ||
89 | enum dma_data_direction dir) | ||
90 | { | ||
91 | return dma_map_single(dev, page_address(page) + offset, size, dir); | ||
92 | } | ||
93 | |||
94 | static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, | ||
95 | size_t size, enum dma_data_direction dir) | ||
96 | { | ||
97 | dma_unmap_single(dev, dma_address, size, dir); | ||
98 | } | ||
99 | |||
100 | static inline void __dma_sync_single(struct device *dev, dma_addr_t dma_handle, | ||
101 | size_t size, enum dma_data_direction dir) | ||
102 | { | 52 | { |
103 | #if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT) | 53 | /* |
104 | if (dev->bus == &pci_bus_type) | 54 | * Each processor family will define its own L1_CACHE_SHIFT, |
105 | return; | 55 | * L1_CACHE_BYTES wraps to this, so this is always safe. |
106 | #endif | 56 | */ |
107 | dma_cache_sync(dev, phys_to_virt(dma_handle), size, dir); | 57 | return L1_CACHE_BYTES; |
108 | } | 58 | } |
109 | 59 | ||
110 | static inline void dma_sync_single_range(struct device *dev, | 60 | static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) |
111 | dma_addr_t dma_handle, | ||
112 | unsigned long offset, size_t size, | ||
113 | enum dma_data_direction dir) | ||
114 | { | 61 | { |
115 | #if defined(CONFIG_PCI) && !defined(CONFIG_SH_PCIDMA_NONCOHERENT) | 62 | struct dma_map_ops *ops = get_dma_ops(dev); |
116 | if (dev->bus == &pci_bus_type) | ||
117 | return; | ||
118 | #endif | ||
119 | dma_cache_sync(dev, phys_to_virt(dma_handle) + offset, size, dir); | ||
120 | } | ||
121 | 63 | ||
122 | static inline void __dma_sync_sg(struct device *dev, struct scatterlist *sg, | 64 | if (ops->mapping_error) |
123 | int nelems, enum dma_data_direction dir) | 65 | return ops->mapping_error(dev, dma_addr); |
124 | { | ||
125 | int i; | ||
126 | 66 | ||
127 | for (i = 0; i < nelems; i++) { | 67 | return dma_addr == 0; |
128 | #if !defined(CONFIG_PCI) || defined(CONFIG_SH_PCIDMA_NONCOHERENT) | ||
129 | dma_cache_sync(dev, sg_virt(&sg[i]), sg[i].length, dir); | ||
130 | #endif | ||
131 | sg[i].dma_address = sg_phys(&sg[i]); | ||
132 | sg[i].dma_length = sg[i].length; | ||
133 | } | ||
134 | } | 68 | } |
135 | 69 | ||
136 | static inline void dma_sync_single_for_cpu(struct device *dev, | 70 | static inline void *dma_alloc_coherent(struct device *dev, size_t size, |
137 | dma_addr_t dma_handle, size_t size, | 71 | dma_addr_t *dma_handle, gfp_t gfp) |
138 | enum dma_data_direction dir) | ||
139 | { | 72 | { |
140 | __dma_sync_single(dev, dma_handle, size, dir); | 73 | struct dma_map_ops *ops = get_dma_ops(dev); |
141 | debug_dma_sync_single_for_cpu(dev, dma_handle, size, dir); | 74 | void *memory; |
142 | } | ||
143 | 75 | ||
144 | static inline void dma_sync_single_for_device(struct device *dev, | 76 | if (dma_alloc_from_coherent(dev, size, dma_handle, &memory)) |
145 | dma_addr_t dma_handle, | 77 | return memory; |
146 | size_t size, | 78 | if (!ops->alloc_coherent) |
147 | enum dma_data_direction dir) | 79 | return NULL; |
148 | { | ||
149 | __dma_sync_single(dev, dma_handle, size, dir); | ||
150 | debug_dma_sync_single_for_device(dev, dma_handle, size, dir); | ||
151 | } | ||
152 | 80 | ||
153 | static inline void dma_sync_single_range_for_cpu(struct device *dev, | 81 | memory = ops->alloc_coherent(dev, size, dma_handle, gfp); |
154 | dma_addr_t dma_handle, | 82 | debug_dma_alloc_coherent(dev, size, *dma_handle, memory); |
155 | unsigned long offset, | ||
156 | size_t size, | ||
157 | enum dma_data_direction direction) | ||
158 | { | ||
159 | dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction); | ||
160 | debug_dma_sync_single_range_for_cpu(dev, dma_handle, | ||
161 | offset, size, direction); | ||
162 | } | ||
163 | 83 | ||
164 | static inline void dma_sync_single_range_for_device(struct device *dev, | 84 | return memory; |
165 | dma_addr_t dma_handle, | ||
166 | unsigned long offset, | ||
167 | size_t size, | ||
168 | enum dma_data_direction direction) | ||
169 | { | ||
170 | dma_sync_single_for_device(dev, dma_handle+offset, size, direction); | ||
171 | debug_dma_sync_single_range_for_device(dev, dma_handle, | ||
172 | offset, size, direction); | ||
173 | } | 85 | } |
174 | 86 | ||
175 | 87 | static inline void dma_free_coherent(struct device *dev, size_t size, | |
176 | static inline void dma_sync_sg_for_cpu(struct device *dev, | 88 | void *vaddr, dma_addr_t dma_handle) |
177 | struct scatterlist *sg, int nelems, | ||
178 | enum dma_data_direction dir) | ||
179 | { | 89 | { |
180 | __dma_sync_sg(dev, sg, nelems, dir); | 90 | struct dma_map_ops *ops = get_dma_ops(dev); |
181 | debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir); | ||
182 | } | ||
183 | 91 | ||
184 | static inline void dma_sync_sg_for_device(struct device *dev, | 92 | WARN_ON(irqs_disabled()); /* for portability */ |
185 | struct scatterlist *sg, int nelems, | ||
186 | enum dma_data_direction dir) | ||
187 | { | ||
188 | __dma_sync_sg(dev, sg, nelems, dir); | ||
189 | debug_dma_sync_sg_for_device(dev, sg, nelems, dir); | ||
190 | } | ||
191 | 93 | ||
192 | static inline int dma_get_cache_alignment(void) | 94 | if (dma_release_from_coherent(dev, get_order(size), vaddr)) |
193 | { | 95 | return; |
194 | /* | ||
195 | * Each processor family will define its own L1_CACHE_SHIFT, | ||
196 | * L1_CACHE_BYTES wraps to this, so this is always safe. | ||
197 | */ | ||
198 | return L1_CACHE_BYTES; | ||
199 | } | ||
200 | 96 | ||
201 | static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) | 97 | debug_dma_free_coherent(dev, size, vaddr, dma_handle); |
202 | { | 98 | if (ops->free_coherent) |
203 | return dma_addr == 0; | 99 | ops->free_coherent(dev, size, vaddr, dma_handle); |
204 | } | 100 | } |
205 | 101 | ||
206 | #define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY | 102 | /* arch/sh/mm/consistent.c */ |
207 | 103 | extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, | |
208 | extern int | 104 | dma_addr_t *dma_addr, gfp_t flag); |
209 | dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr, | 105 | extern void dma_generic_free_coherent(struct device *dev, size_t size, |
210 | dma_addr_t device_addr, size_t size, int flags); | 106 | void *vaddr, dma_addr_t dma_handle); |
211 | |||
212 | extern void | ||
213 | dma_release_declared_memory(struct device *dev); | ||
214 | |||
215 | extern void * | ||
216 | dma_mark_declared_memory_occupied(struct device *dev, | ||
217 | dma_addr_t device_addr, size_t size); | ||
218 | 107 | ||
219 | #endif /* __ASM_SH_DMA_MAPPING_H */ | 108 | #endif /* __ASM_SH_DMA_MAPPING_H */ |
diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h index ced6795891a6..bdccbbfdc0bd 100644 --- a/arch/sh/include/asm/dwarf.h +++ b/arch/sh/include/asm/dwarf.h | |||
@@ -194,6 +194,12 @@ | |||
194 | #define DWARF_ARCH_RA_REG 17 | 194 | #define DWARF_ARCH_RA_REG 17 |
195 | 195 | ||
196 | #ifndef __ASSEMBLY__ | 196 | #ifndef __ASSEMBLY__ |
197 | |||
198 | #include <linux/compiler.h> | ||
199 | #include <linux/bug.h> | ||
200 | #include <linux/list.h> | ||
201 | #include <linux/module.h> | ||
202 | |||
197 | /* | 203 | /* |
198 | * Read either the frame pointer (r14) or the stack pointer (r15). | 204 | * Read either the frame pointer (r14) or the stack pointer (r15). |
199 | * NOTE: this MUST be inlined. | 205 | * NOTE: this MUST be inlined. |
@@ -241,6 +247,12 @@ struct dwarf_cie { | |||
241 | 247 | ||
242 | unsigned long flags; | 248 | unsigned long flags; |
243 | #define DWARF_CIE_Z_AUGMENTATION (1 << 0) | 249 | #define DWARF_CIE_Z_AUGMENTATION (1 << 0) |
250 | |||
251 | /* | ||
252 | * 'mod' will be non-NULL if this CIE came from a module's | ||
253 | * .eh_frame section. | ||
254 | */ | ||
255 | struct module *mod; | ||
244 | }; | 256 | }; |
245 | 257 | ||
246 | /** | 258 | /** |
@@ -255,6 +267,12 @@ struct dwarf_fde { | |||
255 | unsigned char *instructions; | 267 | unsigned char *instructions; |
256 | unsigned char *end; | 268 | unsigned char *end; |
257 | struct list_head link; | 269 | struct list_head link; |
270 | |||
271 | /* | ||
272 | * 'mod' will be non-NULL if this FDE came from a module's | ||
273 | * .eh_frame section. | ||
274 | */ | ||
275 | struct module *mod; | ||
258 | }; | 276 | }; |
259 | 277 | ||
260 | /** | 278 | /** |
@@ -364,6 +382,12 @@ static inline unsigned int DW_CFA_operand(unsigned long insn) | |||
364 | 382 | ||
365 | extern struct dwarf_frame *dwarf_unwind_stack(unsigned long, | 383 | extern struct dwarf_frame *dwarf_unwind_stack(unsigned long, |
366 | struct dwarf_frame *); | 384 | struct dwarf_frame *); |
385 | extern void dwarf_free_frame(struct dwarf_frame *); | ||
386 | |||
387 | extern int module_dwarf_finalize(const Elf_Ehdr *, const Elf_Shdr *, | ||
388 | struct module *); | ||
389 | extern void module_dwarf_cleanup(struct module *); | ||
390 | |||
367 | #endif /* !__ASSEMBLY__ */ | 391 | #endif /* !__ASSEMBLY__ */ |
368 | 392 | ||
369 | #define CFI_STARTPROC .cfi_startproc | 393 | #define CFI_STARTPROC .cfi_startproc |
@@ -391,6 +415,10 @@ extern struct dwarf_frame *dwarf_unwind_stack(unsigned long, | |||
391 | static inline void dwarf_unwinder_init(void) | 415 | static inline void dwarf_unwinder_init(void) |
392 | { | 416 | { |
393 | } | 417 | } |
418 | |||
419 | #define module_dwarf_finalize(hdr, sechdrs, me) (0) | ||
420 | #define module_dwarf_cleanup(mod) do { } while (0) | ||
421 | |||
394 | #endif | 422 | #endif |
395 | 423 | ||
396 | #endif /* CONFIG_DWARF_UNWINDER */ | 424 | #endif /* CONFIG_DWARF_UNWINDER */ |
diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h index 721fcc4d5e98..5ac1e40a511c 100644 --- a/arch/sh/include/asm/fixmap.h +++ b/arch/sh/include/asm/fixmap.h | |||
@@ -14,9 +14,9 @@ | |||
14 | #define _ASM_FIXMAP_H | 14 | #define _ASM_FIXMAP_H |
15 | 15 | ||
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/threads.h> | ||
17 | #include <asm/page.h> | 18 | #include <asm/page.h> |
18 | #ifdef CONFIG_HIGHMEM | 19 | #ifdef CONFIG_HIGHMEM |
19 | #include <linux/threads.h> | ||
20 | #include <asm/kmap_types.h> | 20 | #include <asm/kmap_types.h> |
21 | #endif | 21 | #endif |
22 | 22 | ||
@@ -46,9 +46,15 @@ | |||
46 | * fix-mapped? | 46 | * fix-mapped? |
47 | */ | 47 | */ |
48 | enum fixed_addresses { | 48 | enum fixed_addresses { |
49 | #define FIX_N_COLOURS 16 | 49 | /* |
50 | * The FIX_CMAP entries are used by kmap_coherent() to get virtual | ||
51 | * addresses which are of a known color, and so their values are | ||
52 | * important. __fix_to_virt(FIX_CMAP_END - n) must give an address | ||
53 | * which is the same color as a page (n<<PAGE_SHIFT). | ||
54 | */ | ||
55 | #define FIX_N_COLOURS 8 | ||
50 | FIX_CMAP_BEGIN, | 56 | FIX_CMAP_BEGIN, |
51 | FIX_CMAP_END = FIX_CMAP_BEGIN + FIX_N_COLOURS, | 57 | FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS) - 1, |
52 | FIX_UNCACHED, | 58 | FIX_UNCACHED, |
53 | #ifdef CONFIG_HIGHMEM | 59 | #ifdef CONFIG_HIGHMEM |
54 | FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ | 60 | FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ |
diff --git a/arch/sh/include/asm/fpu.h b/arch/sh/include/asm/fpu.h index 1d3aee04b5cc..fb6bbb9b1cc8 100644 --- a/arch/sh/include/asm/fpu.h +++ b/arch/sh/include/asm/fpu.h | |||
@@ -18,16 +18,15 @@ static inline void grab_fpu(struct pt_regs *regs) | |||
18 | 18 | ||
19 | struct task_struct; | 19 | struct task_struct; |
20 | 20 | ||
21 | extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs); | 21 | extern void save_fpu(struct task_struct *__tsk); |
22 | void fpu_state_restore(struct pt_regs *regs); | ||
22 | #else | 23 | #else |
23 | 24 | ||
25 | #define save_fpu(tsk) do { } while (0) | ||
24 | #define release_fpu(regs) do { } while (0) | 26 | #define release_fpu(regs) do { } while (0) |
25 | #define grab_fpu(regs) do { } while (0) | 27 | #define grab_fpu(regs) do { } while (0) |
28 | #define fpu_state_restore(regs) do { } while (0) | ||
26 | 29 | ||
27 | static inline void save_fpu(struct task_struct *tsk, struct pt_regs *regs) | ||
28 | { | ||
29 | clear_tsk_thread_flag(tsk, TIF_USEDFPU); | ||
30 | } | ||
31 | #endif | 30 | #endif |
32 | 31 | ||
33 | struct user_regset; | 32 | struct user_regset; |
@@ -39,19 +38,28 @@ extern int fpregs_get(struct task_struct *target, | |||
39 | unsigned int pos, unsigned int count, | 38 | unsigned int pos, unsigned int count, |
40 | void *kbuf, void __user *ubuf); | 39 | void *kbuf, void __user *ubuf); |
41 | 40 | ||
41 | static inline void __unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) | ||
42 | { | ||
43 | if (task_thread_info(tsk)->status & TS_USEDFPU) { | ||
44 | task_thread_info(tsk)->status &= ~TS_USEDFPU; | ||
45 | save_fpu(tsk); | ||
46 | release_fpu(regs); | ||
47 | } else | ||
48 | tsk->fpu_counter = 0; | ||
49 | } | ||
50 | |||
42 | static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) | 51 | static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) |
43 | { | 52 | { |
44 | preempt_disable(); | 53 | preempt_disable(); |
45 | if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) | 54 | __unlazy_fpu(tsk, regs); |
46 | save_fpu(tsk, regs); | ||
47 | preempt_enable(); | 55 | preempt_enable(); |
48 | } | 56 | } |
49 | 57 | ||
50 | static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs) | 58 | static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs) |
51 | { | 59 | { |
52 | preempt_disable(); | 60 | preempt_disable(); |
53 | if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { | 61 | if (task_thread_info(tsk)->status & TS_USEDFPU) { |
54 | clear_tsk_thread_flag(tsk, TIF_USEDFPU); | 62 | task_thread_info(tsk)->status &= ~TS_USEDFPU; |
55 | release_fpu(regs); | 63 | release_fpu(regs); |
56 | } | 64 | } |
57 | preempt_enable(); | 65 | preempt_enable(); |
diff --git a/arch/sh/include/asm/ftrace.h b/arch/sh/include/asm/ftrace.h index 12f3a31f20af..13e9966464c2 100644 --- a/arch/sh/include/asm/ftrace.h +++ b/arch/sh/include/asm/ftrace.h | |||
@@ -35,4 +35,21 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) | |||
35 | #endif /* __ASSEMBLY__ */ | 35 | #endif /* __ASSEMBLY__ */ |
36 | #endif /* CONFIG_FUNCTION_TRACER */ | 36 | #endif /* CONFIG_FUNCTION_TRACER */ |
37 | 37 | ||
38 | #ifndef __ASSEMBLY__ | ||
39 | |||
40 | /* arch/sh/kernel/return_address.c */ | ||
41 | extern void *return_address(unsigned int); | ||
42 | |||
43 | #define HAVE_ARCH_CALLER_ADDR | ||
44 | |||
45 | #define CALLER_ADDR0 ((unsigned long)__builtin_return_address(0)) | ||
46 | #define CALLER_ADDR1 ((unsigned long)return_address(1)) | ||
47 | #define CALLER_ADDR2 ((unsigned long)return_address(2)) | ||
48 | #define CALLER_ADDR3 ((unsigned long)return_address(3)) | ||
49 | #define CALLER_ADDR4 ((unsigned long)return_address(4)) | ||
50 | #define CALLER_ADDR5 ((unsigned long)return_address(5)) | ||
51 | #define CALLER_ADDR6 ((unsigned long)return_address(6)) | ||
52 | |||
53 | #endif /* __ASSEMBLY__ */ | ||
54 | |||
38 | #endif /* __ASM_SH_FTRACE_H */ | 55 | #endif /* __ASM_SH_FTRACE_H */ |
diff --git a/arch/sh/include/asm/gpio.h b/arch/sh/include/asm/gpio.h index 61f93da2c62e..f8d9a731e903 100644 --- a/arch/sh/include/asm/gpio.h +++ b/arch/sh/include/asm/gpio.h | |||
@@ -20,7 +20,7 @@ | |||
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #define ARCH_NR_GPIOS 512 | 22 | #define ARCH_NR_GPIOS 512 |
23 | #include <asm-generic/gpio.h> | 23 | #include <linux/sh_pfc.h> |
24 | 24 | ||
25 | #ifdef CONFIG_GPIOLIB | 25 | #ifdef CONFIG_GPIOLIB |
26 | 26 | ||
@@ -53,84 +53,4 @@ static inline int irq_to_gpio(unsigned int irq) | |||
53 | 53 | ||
54 | #endif /* CONFIG_GPIOLIB */ | 54 | #endif /* CONFIG_GPIOLIB */ |
55 | 55 | ||
56 | typedef unsigned short pinmux_enum_t; | ||
57 | typedef unsigned short pinmux_flag_t; | ||
58 | |||
59 | #define PINMUX_TYPE_NONE 0 | ||
60 | #define PINMUX_TYPE_FUNCTION 1 | ||
61 | #define PINMUX_TYPE_GPIO 2 | ||
62 | #define PINMUX_TYPE_OUTPUT 3 | ||
63 | #define PINMUX_TYPE_INPUT 4 | ||
64 | #define PINMUX_TYPE_INPUT_PULLUP 5 | ||
65 | #define PINMUX_TYPE_INPUT_PULLDOWN 6 | ||
66 | |||
67 | #define PINMUX_FLAG_TYPE (0x7) | ||
68 | #define PINMUX_FLAG_WANT_PULLUP (1 << 3) | ||
69 | #define PINMUX_FLAG_WANT_PULLDOWN (1 << 4) | ||
70 | |||
71 | #define PINMUX_FLAG_DBIT_SHIFT 5 | ||
72 | #define PINMUX_FLAG_DBIT (0x1f << PINMUX_FLAG_DBIT_SHIFT) | ||
73 | #define PINMUX_FLAG_DREG_SHIFT 10 | ||
74 | #define PINMUX_FLAG_DREG (0x3f << PINMUX_FLAG_DREG_SHIFT) | ||
75 | |||
76 | struct pinmux_gpio { | ||
77 | pinmux_enum_t enum_id; | ||
78 | pinmux_flag_t flags; | ||
79 | }; | ||
80 | |||
81 | #define PINMUX_GPIO(gpio, data_or_mark) [gpio] = { data_or_mark } | ||
82 | #define PINMUX_DATA(data_or_mark, ids...) data_or_mark, ids, 0 | ||
83 | |||
84 | struct pinmux_cfg_reg { | ||
85 | unsigned long reg, reg_width, field_width; | ||
86 | unsigned long *cnt; | ||
87 | pinmux_enum_t *enum_ids; | ||
88 | }; | ||
89 | |||
90 | #define PINMUX_CFG_REG(name, r, r_width, f_width) \ | ||
91 | .reg = r, .reg_width = r_width, .field_width = f_width, \ | ||
92 | .cnt = (unsigned long [r_width / f_width]) {}, \ | ||
93 | .enum_ids = (pinmux_enum_t [(r_width / f_width) * (1 << f_width)]) \ | ||
94 | |||
95 | struct pinmux_data_reg { | ||
96 | unsigned long reg, reg_width, reg_shadow; | ||
97 | pinmux_enum_t *enum_ids; | ||
98 | }; | ||
99 | |||
100 | #define PINMUX_DATA_REG(name, r, r_width) \ | ||
101 | .reg = r, .reg_width = r_width, \ | ||
102 | .enum_ids = (pinmux_enum_t [r_width]) \ | ||
103 | |||
104 | struct pinmux_range { | ||
105 | pinmux_enum_t begin; | ||
106 | pinmux_enum_t end; | ||
107 | pinmux_enum_t force; | ||
108 | }; | ||
109 | |||
110 | struct pinmux_info { | ||
111 | char *name; | ||
112 | pinmux_enum_t reserved_id; | ||
113 | struct pinmux_range data; | ||
114 | struct pinmux_range input; | ||
115 | struct pinmux_range input_pd; | ||
116 | struct pinmux_range input_pu; | ||
117 | struct pinmux_range output; | ||
118 | struct pinmux_range mark; | ||
119 | struct pinmux_range function; | ||
120 | |||
121 | unsigned first_gpio, last_gpio; | ||
122 | |||
123 | struct pinmux_gpio *gpios; | ||
124 | struct pinmux_cfg_reg *cfg_regs; | ||
125 | struct pinmux_data_reg *data_regs; | ||
126 | |||
127 | pinmux_enum_t *gpio_data; | ||
128 | unsigned int gpio_data_size; | ||
129 | |||
130 | unsigned long *gpio_in_use; | ||
131 | struct gpio_chip chip; | ||
132 | }; | ||
133 | |||
134 | int register_pinmux(struct pinmux_info *pip); | ||
135 | |||
136 | #endif /* __ASM_SH_GPIO_H */ | 56 | #endif /* __ASM_SH_GPIO_H */ |
diff --git a/arch/sh/include/asm/hardirq.h b/arch/sh/include/asm/hardirq.h index a5be4afa790b..48b191313a99 100644 --- a/arch/sh/include/asm/hardirq.h +++ b/arch/sh/include/asm/hardirq.h | |||
@@ -1,9 +1,16 @@ | |||
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 | extern void ack_bad_irq(unsigned int irq); | 4 | #include <linux/threads.h> |
5 | #define ack_bad_irq ack_bad_irq | 5 | #include <linux/irq.h> |
6 | |||
7 | typedef struct { | ||
8 | unsigned int __softirq_pending; | ||
9 | unsigned int __nmi_count; /* arch dependent */ | ||
10 | } ____cacheline_aligned irq_cpustat_t; | ||
6 | 11 | ||
7 | #include <asm-generic/hardirq.h> | 12 | #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ |
13 | |||
14 | extern void ack_bad_irq(unsigned int irq); | ||
8 | 15 | ||
9 | #endif /* __ASM_SH_HARDIRQ_H */ | 16 | #endif /* __ASM_SH_HARDIRQ_H */ |
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h index 5be45ea4dfec..512cd3e9d0ca 100644 --- a/arch/sh/include/asm/io.h +++ b/arch/sh/include/asm/io.h | |||
@@ -90,15 +90,11 @@ | |||
90 | #define ctrl_outl __raw_writel | 90 | #define ctrl_outl __raw_writel |
91 | #define ctrl_outq __raw_writeq | 91 | #define ctrl_outq __raw_writeq |
92 | 92 | ||
93 | extern unsigned long generic_io_base; | ||
94 | |||
93 | static inline void ctrl_delay(void) | 95 | static inline void ctrl_delay(void) |
94 | { | 96 | { |
95 | #ifdef CONFIG_CPU_SH4 | 97 | __raw_readw(generic_io_base); |
96 | __raw_readw(CCN_PVR); | ||
97 | #elif defined(P2SEG) | ||
98 | __raw_readw(P2SEG); | ||
99 | #else | ||
100 | #error "Need a dummy address for delay" | ||
101 | #endif | ||
102 | } | 98 | } |
103 | 99 | ||
104 | #define __BUILD_MEMORY_STRING(bwlq, type) \ | 100 | #define __BUILD_MEMORY_STRING(bwlq, type) \ |
@@ -186,8 +182,6 @@ __BUILD_MEMORY_STRING(q, u64) | |||
186 | 182 | ||
187 | #define IO_SPACE_LIMIT 0xffffffff | 183 | #define IO_SPACE_LIMIT 0xffffffff |
188 | 184 | ||
189 | extern unsigned long generic_io_base; | ||
190 | |||
191 | /* | 185 | /* |
192 | * This function provides a method for the generic case where a | 186 | * This function provides a method for the generic case where a |
193 | * board-specific ioport_map simply needs to return the port + some | 187 | * board-specific ioport_map simply needs to return the port + some |
@@ -246,7 +240,7 @@ void __iounmap(void __iomem *addr); | |||
246 | static inline void __iomem * | 240 | static inline void __iomem * |
247 | __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) | 241 | __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) |
248 | { | 242 | { |
249 | #if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) | 243 | #if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB) |
250 | unsigned long last_addr = offset + size - 1; | 244 | unsigned long last_addr = offset + size - 1; |
251 | #endif | 245 | #endif |
252 | void __iomem *ret; | 246 | void __iomem *ret; |
@@ -255,7 +249,7 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) | |||
255 | if (ret) | 249 | if (ret) |
256 | return ret; | 250 | return ret; |
257 | 251 | ||
258 | #if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) | 252 | #if defined(CONFIG_SUPERH32) && !defined(CONFIG_PMB_FIXED) && !defined(CONFIG_PMB) |
259 | /* | 253 | /* |
260 | * For P1 and P2 space this is trivial, as everything is already | 254 | * For P1 and P2 space this is trivial, as everything is already |
261 | * mapped. Uncached access for P1 addresses are done through P2. | 255 | * mapped. Uncached access for P1 addresses are done through P2. |
diff --git a/arch/sh/include/asm/irqflags.h b/arch/sh/include/asm/irqflags.h index 46e71da5be6b..a741153b41c2 100644 --- a/arch/sh/include/asm/irqflags.h +++ b/arch/sh/include/asm/irqflags.h | |||
@@ -1,34 +1,9 @@ | |||
1 | #ifndef __ASM_SH_IRQFLAGS_H | 1 | #ifndef __ASM_SH_IRQFLAGS_H |
2 | #define __ASM_SH_IRQFLAGS_H | 2 | #define __ASM_SH_IRQFLAGS_H |
3 | 3 | ||
4 | #ifdef CONFIG_SUPERH32 | 4 | #define RAW_IRQ_DISABLED 0xf0 |
5 | #include "irqflags_32.h" | 5 | #define RAW_IRQ_ENABLED 0x00 |
6 | #else | ||
7 | #include "irqflags_64.h" | ||
8 | #endif | ||
9 | 6 | ||
10 | #define raw_local_save_flags(flags) \ | 7 | #include <asm-generic/irqflags.h> |
11 | do { (flags) = __raw_local_save_flags(); } while (0) | ||
12 | |||
13 | static inline int raw_irqs_disabled_flags(unsigned long flags) | ||
14 | { | ||
15 | return (flags != 0); | ||
16 | } | ||
17 | |||
18 | static inline int raw_irqs_disabled(void) | ||
19 | { | ||
20 | unsigned long flags = __raw_local_save_flags(); | ||
21 | |||
22 | return raw_irqs_disabled_flags(flags); | ||
23 | } | ||
24 | |||
25 | #define raw_local_irq_save(flags) \ | ||
26 | do { (flags) = __raw_local_irq_save(); } while (0) | ||
27 | |||
28 | static inline void raw_local_irq_restore(unsigned long flags) | ||
29 | { | ||
30 | if ((flags & 0xf0) != 0xf0) | ||
31 | raw_local_irq_enable(); | ||
32 | } | ||
33 | 8 | ||
34 | #endif /* __ASM_SH_IRQFLAGS_H */ | 9 | #endif /* __ASM_SH_IRQFLAGS_H */ |
diff --git a/arch/sh/include/asm/irqflags_32.h b/arch/sh/include/asm/irqflags_32.h deleted file mode 100644 index 60218f541340..000000000000 --- a/arch/sh/include/asm/irqflags_32.h +++ /dev/null | |||
@@ -1,99 +0,0 @@ | |||
1 | #ifndef __ASM_SH_IRQFLAGS_32_H | ||
2 | #define __ASM_SH_IRQFLAGS_32_H | ||
3 | |||
4 | static inline void raw_local_irq_enable(void) | ||
5 | { | ||
6 | unsigned long __dummy0, __dummy1; | ||
7 | |||
8 | __asm__ __volatile__ ( | ||
9 | "stc sr, %0\n\t" | ||
10 | "and %1, %0\n\t" | ||
11 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
12 | "stc r6_bank, %1\n\t" | ||
13 | "or %1, %0\n\t" | ||
14 | #endif | ||
15 | "ldc %0, sr\n\t" | ||
16 | : "=&r" (__dummy0), "=r" (__dummy1) | ||
17 | : "1" (~0x000000f0) | ||
18 | : "memory" | ||
19 | ); | ||
20 | } | ||
21 | |||
22 | static inline void raw_local_irq_disable(void) | ||
23 | { | ||
24 | unsigned long flags; | ||
25 | |||
26 | __asm__ __volatile__ ( | ||
27 | "stc sr, %0\n\t" | ||
28 | "or #0xf0, %0\n\t" | ||
29 | "ldc %0, sr\n\t" | ||
30 | : "=&z" (flags) | ||
31 | : /* no inputs */ | ||
32 | : "memory" | ||
33 | ); | ||
34 | } | ||
35 | |||
36 | static inline void set_bl_bit(void) | ||
37 | { | ||
38 | unsigned long __dummy0, __dummy1; | ||
39 | |||
40 | __asm__ __volatile__ ( | ||
41 | "stc sr, %0\n\t" | ||
42 | "or %2, %0\n\t" | ||
43 | "and %3, %0\n\t" | ||
44 | "ldc %0, sr\n\t" | ||
45 | : "=&r" (__dummy0), "=r" (__dummy1) | ||
46 | : "r" (0x10000000), "r" (0xffffff0f) | ||
47 | : "memory" | ||
48 | ); | ||
49 | } | ||
50 | |||
51 | static inline void clear_bl_bit(void) | ||
52 | { | ||
53 | unsigned long __dummy0, __dummy1; | ||
54 | |||
55 | __asm__ __volatile__ ( | ||
56 | "stc sr, %0\n\t" | ||
57 | "and %2, %0\n\t" | ||
58 | "ldc %0, sr\n\t" | ||
59 | : "=&r" (__dummy0), "=r" (__dummy1) | ||
60 | : "1" (~0x10000000) | ||
61 | : "memory" | ||
62 | ); | ||
63 | } | ||
64 | |||
65 | static inline unsigned long __raw_local_save_flags(void) | ||
66 | { | ||
67 | unsigned long flags; | ||
68 | |||
69 | __asm__ __volatile__ ( | ||
70 | "stc sr, %0\n\t" | ||
71 | "and #0xf0, %0\n\t" | ||
72 | : "=&z" (flags) | ||
73 | : /* no inputs */ | ||
74 | : "memory" | ||
75 | ); | ||
76 | |||
77 | return flags; | ||
78 | } | ||
79 | |||
80 | static inline unsigned long __raw_local_irq_save(void) | ||
81 | { | ||
82 | unsigned long flags, __dummy; | ||
83 | |||
84 | __asm__ __volatile__ ( | ||
85 | "stc sr, %1\n\t" | ||
86 | "mov %1, %0\n\t" | ||
87 | "or #0xf0, %0\n\t" | ||
88 | "ldc %0, sr\n\t" | ||
89 | "mov %1, %0\n\t" | ||
90 | "and #0xf0, %0\n\t" | ||
91 | : "=&z" (flags), "=&r" (__dummy) | ||
92 | : /* no inputs */ | ||
93 | : "memory" | ||
94 | ); | ||
95 | |||
96 | return flags; | ||
97 | } | ||
98 | |||
99 | #endif /* __ASM_SH_IRQFLAGS_32_H */ | ||
diff --git a/arch/sh/include/asm/irqflags_64.h b/arch/sh/include/asm/irqflags_64.h deleted file mode 100644 index 88f65222c1d4..000000000000 --- a/arch/sh/include/asm/irqflags_64.h +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | #ifndef __ASM_SH_IRQFLAGS_64_H | ||
2 | #define __ASM_SH_IRQFLAGS_64_H | ||
3 | |||
4 | #include <cpu/registers.h> | ||
5 | |||
6 | #define SR_MASK_LL 0x00000000000000f0LL | ||
7 | #define SR_BL_LL 0x0000000010000000LL | ||
8 | |||
9 | static inline void raw_local_irq_enable(void) | ||
10 | { | ||
11 | unsigned long long __dummy0, __dummy1 = ~SR_MASK_LL; | ||
12 | |||
13 | __asm__ __volatile__("getcon " __SR ", %0\n\t" | ||
14 | "and %0, %1, %0\n\t" | ||
15 | "putcon %0, " __SR "\n\t" | ||
16 | : "=&r" (__dummy0) | ||
17 | : "r" (__dummy1)); | ||
18 | } | ||
19 | |||
20 | static inline void raw_local_irq_disable(void) | ||
21 | { | ||
22 | unsigned long long __dummy0, __dummy1 = SR_MASK_LL; | ||
23 | |||
24 | __asm__ __volatile__("getcon " __SR ", %0\n\t" | ||
25 | "or %0, %1, %0\n\t" | ||
26 | "putcon %0, " __SR "\n\t" | ||
27 | : "=&r" (__dummy0) | ||
28 | : "r" (__dummy1)); | ||
29 | } | ||
30 | |||
31 | static inline void set_bl_bit(void) | ||
32 | { | ||
33 | unsigned long long __dummy0, __dummy1 = SR_BL_LL; | ||
34 | |||
35 | __asm__ __volatile__("getcon " __SR ", %0\n\t" | ||
36 | "or %0, %1, %0\n\t" | ||
37 | "putcon %0, " __SR "\n\t" | ||
38 | : "=&r" (__dummy0) | ||
39 | : "r" (__dummy1)); | ||
40 | |||
41 | } | ||
42 | |||
43 | static inline void clear_bl_bit(void) | ||
44 | { | ||
45 | unsigned long long __dummy0, __dummy1 = ~SR_BL_LL; | ||
46 | |||
47 | __asm__ __volatile__("getcon " __SR ", %0\n\t" | ||
48 | "and %0, %1, %0\n\t" | ||
49 | "putcon %0, " __SR "\n\t" | ||
50 | : "=&r" (__dummy0) | ||
51 | : "r" (__dummy1)); | ||
52 | } | ||
53 | |||
54 | static inline unsigned long __raw_local_save_flags(void) | ||
55 | { | ||
56 | unsigned long long __dummy = SR_MASK_LL; | ||
57 | unsigned long flags; | ||
58 | |||
59 | __asm__ __volatile__ ( | ||
60 | "getcon " __SR ", %0\n\t" | ||
61 | "and %0, %1, %0" | ||
62 | : "=&r" (flags) | ||
63 | : "r" (__dummy)); | ||
64 | |||
65 | return flags; | ||
66 | } | ||
67 | |||
68 | static inline unsigned long __raw_local_irq_save(void) | ||
69 | { | ||
70 | unsigned long long __dummy0, __dummy1 = SR_MASK_LL; | ||
71 | unsigned long flags; | ||
72 | |||
73 | __asm__ __volatile__ ( | ||
74 | "getcon " __SR ", %1\n\t" | ||
75 | "or %1, r63, %0\n\t" | ||
76 | "or %1, %2, %1\n\t" | ||
77 | "putcon %1, " __SR "\n\t" | ||
78 | "and %0, %2, %0" | ||
79 | : "=&r" (flags), "=&r" (__dummy0) | ||
80 | : "r" (__dummy1)); | ||
81 | |||
82 | return flags; | ||
83 | } | ||
84 | |||
85 | #endif /* __ASM_SH_IRQFLAGS_64_H */ | ||
diff --git a/arch/sh/include/asm/mmu.h b/arch/sh/include/asm/mmu.h index f5963037c9d6..c7426ad9926e 100644 --- a/arch/sh/include/asm/mmu.h +++ b/arch/sh/include/asm/mmu.h | |||
@@ -7,12 +7,16 @@ | |||
7 | #define PMB_PASCR 0xff000070 | 7 | #define PMB_PASCR 0xff000070 |
8 | #define PMB_IRMCR 0xff000078 | 8 | #define PMB_IRMCR 0xff000078 |
9 | 9 | ||
10 | #define PASCR_SE 0x80000000 | ||
11 | |||
10 | #define PMB_ADDR 0xf6100000 | 12 | #define PMB_ADDR 0xf6100000 |
11 | #define PMB_DATA 0xf7100000 | 13 | #define PMB_DATA 0xf7100000 |
12 | #define PMB_ENTRY_MAX 16 | 14 | #define PMB_ENTRY_MAX 16 |
13 | #define PMB_E_MASK 0x0000000f | 15 | #define PMB_E_MASK 0x0000000f |
14 | #define PMB_E_SHIFT 8 | 16 | #define PMB_E_SHIFT 8 |
15 | 17 | ||
18 | #define PMB_PFN_MASK 0xff000000 | ||
19 | |||
16 | #define PMB_SZ_16M 0x00000000 | 20 | #define PMB_SZ_16M 0x00000000 |
17 | #define PMB_SZ_64M 0x00000010 | 21 | #define PMB_SZ_64M 0x00000010 |
18 | #define PMB_SZ_128M 0x00000080 | 22 | #define PMB_SZ_128M 0x00000080 |
@@ -62,17 +66,10 @@ struct pmb_entry { | |||
62 | }; | 66 | }; |
63 | 67 | ||
64 | /* arch/sh/mm/pmb.c */ | 68 | /* arch/sh/mm/pmb.c */ |
65 | int __set_pmb_entry(unsigned long vpn, unsigned long ppn, | ||
66 | unsigned long flags, int *entry); | ||
67 | int set_pmb_entry(struct pmb_entry *pmbe); | ||
68 | void clear_pmb_entry(struct pmb_entry *pmbe); | ||
69 | struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn, | ||
70 | unsigned long flags); | ||
71 | void pmb_free(struct pmb_entry *pmbe); | ||
72 | long pmb_remap(unsigned long virt, unsigned long phys, | 69 | long pmb_remap(unsigned long virt, unsigned long phys, |
73 | unsigned long size, unsigned long flags); | 70 | unsigned long size, unsigned long flags); |
74 | void pmb_unmap(unsigned long addr); | 71 | void pmb_unmap(unsigned long addr); |
72 | int pmb_init(void); | ||
75 | #endif /* __ASSEMBLY__ */ | 73 | #endif /* __ASSEMBLY__ */ |
76 | 74 | ||
77 | #endif /* __MMU_H */ | 75 | #endif /* __MMU_H */ |
78 | |||
diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h index 4163950cd1c6..67f3999b544e 100644 --- a/arch/sh/include/asm/pci.h +++ b/arch/sh/include/asm/pci.h | |||
@@ -3,8 +3,6 @@ | |||
3 | 3 | ||
4 | #ifdef __KERNEL__ | 4 | #ifdef __KERNEL__ |
5 | 5 | ||
6 | #include <linux/dma-mapping.h> | ||
7 | |||
8 | /* Can be used to override the logic in pci_scan_bus for skipping | 6 | /* Can be used to override the logic in pci_scan_bus for skipping |
9 | already-configured bus numbers - to be used for buggy BIOSes | 7 | already-configured bus numbers - to be used for buggy BIOSes |
10 | or architectures with incomplete PCI setup by the loader */ | 8 | or architectures with incomplete PCI setup by the loader */ |
@@ -54,30 +52,18 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) | |||
54 | * address space. The networking and block device layers use | 52 | * address space. The networking and block device layers use |
55 | * this boolean for bounce buffer decisions. | 53 | * this boolean for bounce buffer decisions. |
56 | */ | 54 | */ |
57 | #define PCI_DMA_BUS_IS_PHYS (1) | 55 | #define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys) |
58 | |||
59 | #include <linux/types.h> | ||
60 | #include <linux/slab.h> | ||
61 | #include <asm/scatterlist.h> | ||
62 | #include <linux/string.h> | ||
63 | #include <asm/io.h> | ||
64 | 56 | ||
65 | /* pci_unmap_{single,page} being a nop depends upon the | 57 | /* pci_unmap_{single,page} being a nop depends upon the |
66 | * configuration. | 58 | * configuration. |
67 | */ | 59 | */ |
68 | #ifdef CONFIG_SH_PCIDMA_NONCOHERENT | 60 | #ifdef CONFIG_DMA_NONCOHERENT |
69 | #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ | 61 | #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME; |
70 | dma_addr_t ADDR_NAME; | 62 | #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME; |
71 | #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) \ | 63 | #define pci_unmap_addr(PTR, ADDR_NAME) ((PTR)->ADDR_NAME) |
72 | __u32 LEN_NAME; | 64 | #define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) (((PTR)->ADDR_NAME) = (VAL)) |
73 | #define pci_unmap_addr(PTR, ADDR_NAME) \ | 65 | #define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME) |
74 | ((PTR)->ADDR_NAME) | 66 | #define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL)) |
75 | #define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) \ | ||
76 | (((PTR)->ADDR_NAME) = (VAL)) | ||
77 | #define pci_unmap_len(PTR, LEN_NAME) \ | ||
78 | ((PTR)->LEN_NAME) | ||
79 | #define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ | ||
80 | (((PTR)->LEN_NAME) = (VAL)) | ||
81 | #else | 67 | #else |
82 | #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) | 68 | #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) |
83 | #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) | 69 | #define DECLARE_PCI_UNMAP_LEN(LEN_NAME) |
diff --git a/arch/sh/include/asm/perf_event.h b/arch/sh/include/asm/perf_event.h index 11a302297ab7..3d0c9f36d150 100644 --- a/arch/sh/include/asm/perf_event.h +++ b/arch/sh/include/asm/perf_event.h | |||
@@ -1,8 +1,35 @@ | |||
1 | #ifndef __ASM_SH_PERF_EVENT_H | 1 | #ifndef __ASM_SH_PERF_EVENT_H |
2 | #define __ASM_SH_PERF_EVENT_H | 2 | #define __ASM_SH_PERF_EVENT_H |
3 | 3 | ||
4 | /* SH only supports software events through this interface. */ | 4 | struct hw_perf_event; |
5 | static inline void set_perf_event_pending(void) {} | 5 | |
6 | #define MAX_HWEVENTS 2 | ||
7 | |||
8 | struct sh_pmu { | ||
9 | const char *name; | ||
10 | unsigned int num_events; | ||
11 | void (*disable_all)(void); | ||
12 | void (*enable_all)(void); | ||
13 | void (*enable)(struct hw_perf_event *, int); | ||
14 | void (*disable)(struct hw_perf_event *, int); | ||
15 | u64 (*read)(int); | ||
16 | int (*event_map)(int); | ||
17 | unsigned int max_events; | ||
18 | unsigned long raw_event_mask; | ||
19 | const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] | ||
20 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
21 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; | ||
22 | }; | ||
23 | |||
24 | /* arch/sh/kernel/perf_event.c */ | ||
25 | extern int register_sh_pmu(struct sh_pmu *); | ||
26 | extern int reserve_pmc_hardware(void); | ||
27 | extern void release_pmc_hardware(void); | ||
28 | |||
29 | static inline void set_perf_event_pending(void) | ||
30 | { | ||
31 | /* Nothing to see here, move along. */ | ||
32 | } | ||
6 | 33 | ||
7 | #define PERF_EVENT_INDEX_OFFSET 0 | 34 | #define PERF_EVENT_INDEX_OFFSET 0 |
8 | 35 | ||
diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h index 4f3efa7d5a64..ba3046e4f06f 100644 --- a/arch/sh/include/asm/pgtable.h +++ b/arch/sh/include/asm/pgtable.h | |||
@@ -75,13 +75,31 @@ static inline unsigned long long neff_sign_extend(unsigned long val) | |||
75 | #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) | 75 | #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) |
76 | #define FIRST_USER_ADDRESS 0 | 76 | #define FIRST_USER_ADDRESS 0 |
77 | 77 | ||
78 | #ifdef CONFIG_32BIT | 78 | #define PHYS_ADDR_MASK29 0x1fffffff |
79 | #define PHYS_ADDR_MASK 0xffffffff | 79 | #define PHYS_ADDR_MASK32 0xffffffff |
80 | |||
81 | #ifdef CONFIG_PMB | ||
82 | static inline unsigned long phys_addr_mask(void) | ||
83 | { | ||
84 | /* Is the MMU in 29bit mode? */ | ||
85 | if (__in_29bit_mode()) | ||
86 | return PHYS_ADDR_MASK29; | ||
87 | |||
88 | return PHYS_ADDR_MASK32; | ||
89 | } | ||
90 | #elif defined(CONFIG_32BIT) | ||
91 | static inline unsigned long phys_addr_mask(void) | ||
92 | { | ||
93 | return PHYS_ADDR_MASK32; | ||
94 | } | ||
80 | #else | 95 | #else |
81 | #define PHYS_ADDR_MASK 0x1fffffff | 96 | static inline unsigned long phys_addr_mask(void) |
97 | { | ||
98 | return PHYS_ADDR_MASK29; | ||
99 | } | ||
82 | #endif | 100 | #endif |
83 | 101 | ||
84 | #define PTE_PHYS_MASK (PHYS_ADDR_MASK & PAGE_MASK) | 102 | #define PTE_PHYS_MASK (phys_addr_mask() & PAGE_MASK) |
85 | #define PTE_FLAGS_MASK (~(PTE_PHYS_MASK) << PAGE_SHIFT) | 103 | #define PTE_FLAGS_MASK (~(PTE_PHYS_MASK) << PAGE_SHIFT) |
86 | 104 | ||
87 | #ifdef CONFIG_SUPERH32 | 105 | #ifdef CONFIG_SUPERH32 |
diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h index c0d359ce337b..b35435516203 100644 --- a/arch/sh/include/asm/pgtable_32.h +++ b/arch/sh/include/asm/pgtable_32.h | |||
@@ -108,7 +108,7 @@ static inline unsigned long copy_ptea_attributes(unsigned long x) | |||
108 | #define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE) | 108 | #define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE) |
109 | #endif | 109 | #endif |
110 | 110 | ||
111 | #define _PAGE_FLAGS_HARDWARE_MASK (PHYS_ADDR_MASK & ~(_PAGE_CLEAR_FLAGS)) | 111 | #define _PAGE_FLAGS_HARDWARE_MASK (phys_addr_mask() & ~(_PAGE_CLEAR_FLAGS)) |
112 | 112 | ||
113 | /* Hardware flags, page size encoding */ | 113 | /* Hardware flags, page size encoding */ |
114 | #if !defined(CONFIG_MMU) | 114 | #if !defined(CONFIG_MMU) |
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h index 9a8714945dc9..1f3d6fab660c 100644 --- a/arch/sh/include/asm/processor_32.h +++ b/arch/sh/include/asm/processor_32.h | |||
@@ -56,6 +56,7 @@ asmlinkage void __init sh_cpu_init(void); | |||
56 | #define SR_DSP 0x00001000 | 56 | #define SR_DSP 0x00001000 |
57 | #define SR_IMASK 0x000000f0 | 57 | #define SR_IMASK 0x000000f0 |
58 | #define SR_FD 0x00008000 | 58 | #define SR_FD 0x00008000 |
59 | #define SR_MD 0x40000000 | ||
59 | 60 | ||
60 | /* | 61 | /* |
61 | * DSP structure and data | 62 | * DSP structure and data |
@@ -136,7 +137,7 @@ struct mm_struct; | |||
136 | extern void release_thread(struct task_struct *); | 137 | extern void release_thread(struct task_struct *); |
137 | 138 | ||
138 | /* Prepare to copy thread state - unlazy all lazy status */ | 139 | /* Prepare to copy thread state - unlazy all lazy status */ |
139 | #define prepare_to_copy(tsk) do { } while (0) | 140 | void prepare_to_copy(struct task_struct *tsk); |
140 | 141 | ||
141 | /* | 142 | /* |
142 | * create a kernel thread without removing it from tasklists | 143 | * create a kernel thread without removing it from tasklists |
diff --git a/arch/sh/include/asm/scatterlist.h b/arch/sh/include/asm/scatterlist.h index 327cc2e4c97b..e38d1d4c7f6f 100644 --- a/arch/sh/include/asm/scatterlist.h +++ b/arch/sh/include/asm/scatterlist.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef __ASM_SH_SCATTERLIST_H | 1 | #ifndef __ASM_SH_SCATTERLIST_H |
2 | #define __ASM_SH_SCATTERLIST_H | 2 | #define __ASM_SH_SCATTERLIST_H |
3 | 3 | ||
4 | #define ISA_DMA_THRESHOLD PHYS_ADDR_MASK | 4 | #define ISA_DMA_THRESHOLD phys_addr_mask() |
5 | 5 | ||
6 | #include <asm-generic/scatterlist.h> | 6 | #include <asm-generic/scatterlist.h> |
7 | 7 | ||
diff --git a/arch/sh/include/asm/sh_keysc.h b/arch/sh/include/asm/sh_keysc.h deleted file mode 100644 index 4a65b1e40eab..000000000000 --- a/arch/sh/include/asm/sh_keysc.h +++ /dev/null | |||
@@ -1,14 +0,0 @@ | |||
1 | #ifndef __ASM_KEYSC_H__ | ||
2 | #define __ASM_KEYSC_H__ | ||
3 | |||
4 | #define SH_KEYSC_MAXKEYS 30 | ||
5 | |||
6 | struct sh_keysc_info { | ||
7 | enum { SH_KEYSC_MODE_1, SH_KEYSC_MODE_2, SH_KEYSC_MODE_3 } mode; | ||
8 | int scan_timing; /* 0 -> 7, see KYCR1, SCN[2:0] */ | ||
9 | int delay; | ||
10 | int kycr2_delay; | ||
11 | int keycodes[SH_KEYSC_MAXKEYS]; | ||
12 | }; | ||
13 | |||
14 | #endif /* __ASM_KEYSC_H__ */ | ||
diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h index 5c8ea28ff7a4..fe9c2a1ad047 100644 --- a/arch/sh/include/asm/suspend.h +++ b/arch/sh/include/asm/suspend.h | |||
@@ -2,6 +2,7 @@ | |||
2 | #define _ASM_SH_SUSPEND_H | 2 | #define _ASM_SH_SUSPEND_H |
3 | 3 | ||
4 | #ifndef __ASSEMBLY__ | 4 | #ifndef __ASSEMBLY__ |
5 | #include <linux/notifier.h> | ||
5 | static inline int arch_prepare_suspend(void) { return 0; } | 6 | static inline int arch_prepare_suspend(void) { return 0; } |
6 | 7 | ||
7 | #include <asm/ptrace.h> | 8 | #include <asm/ptrace.h> |
@@ -19,6 +20,69 @@ void sh_mobile_setup_cpuidle(void); | |||
19 | static inline void sh_mobile_setup_cpuidle(void) {} | 20 | static inline void sh_mobile_setup_cpuidle(void) {} |
20 | #endif | 21 | #endif |
21 | 22 | ||
23 | /* notifier chains for pre/post sleep hooks */ | ||
24 | extern struct atomic_notifier_head sh_mobile_pre_sleep_notifier_list; | ||
25 | extern struct atomic_notifier_head sh_mobile_post_sleep_notifier_list; | ||
26 | |||
27 | /* priority levels for notifiers */ | ||
28 | #define SH_MOBILE_SLEEP_BOARD 0 | ||
29 | #define SH_MOBILE_SLEEP_CPU 1 | ||
30 | #define SH_MOBILE_PRE(x) (x) | ||
31 | #define SH_MOBILE_POST(x) (-(x)) | ||
32 | |||
33 | /* board code registration function for self-refresh assembly snippets */ | ||
34 | void sh_mobile_register_self_refresh(unsigned long flags, | ||
35 | void *pre_start, void *pre_end, | ||
36 | void *post_start, void *post_end); | ||
37 | |||
38 | /* register structure for address/data information */ | ||
39 | struct sh_sleep_regs { | ||
40 | unsigned long stbcr; | ||
41 | unsigned long bar; | ||
42 | |||
43 | /* MMU */ | ||
44 | unsigned long pteh; | ||
45 | unsigned long ptel; | ||
46 | unsigned long ttb; | ||
47 | unsigned long tea; | ||
48 | unsigned long mmucr; | ||
49 | unsigned long ptea; | ||
50 | unsigned long pascr; | ||
51 | unsigned long irmcr; | ||
52 | |||
53 | /* Cache */ | ||
54 | unsigned long ccr; | ||
55 | unsigned long ramcr; | ||
56 | }; | ||
57 | |||
58 | /* data area for low-level sleep code */ | ||
59 | struct sh_sleep_data { | ||
60 | /* current sleep mode (SUSP_SH_...) */ | ||
61 | unsigned long mode; | ||
62 | |||
63 | /* addresses of board specific self-refresh snippets */ | ||
64 | unsigned long sf_pre; | ||
65 | unsigned long sf_post; | ||
66 | |||
67 | /* address of resume code */ | ||
68 | unsigned long resume; | ||
69 | |||
70 | /* register state saved and restored by the assembly code */ | ||
71 | unsigned long vbr; | ||
72 | unsigned long spc; | ||
73 | unsigned long sr; | ||
74 | unsigned long sp; | ||
75 | |||
76 | /* structure for keeping register addresses */ | ||
77 | struct sh_sleep_regs addr; | ||
78 | |||
79 | /* structure for saving/restoring register state */ | ||
80 | struct sh_sleep_regs data; | ||
81 | }; | ||
82 | |||
83 | /* a bitmap of supported sleep modes (SUSP_SH..) */ | ||
84 | extern unsigned long sh_mobile_sleep_supported; | ||
85 | |||
22 | #endif | 86 | #endif |
23 | 87 | ||
24 | /* flags passed to assembly suspend code */ | 88 | /* flags passed to assembly suspend code */ |
@@ -27,5 +91,6 @@ static inline void sh_mobile_setup_cpuidle(void) {} | |||
27 | #define SUSP_SH_RSTANDBY (1 << 2) /* SH-Mobile R-standby mode */ | 91 | #define SUSP_SH_RSTANDBY (1 << 2) /* SH-Mobile R-standby mode */ |
28 | #define SUSP_SH_USTANDBY (1 << 3) /* SH-Mobile U-standby mode */ | 92 | #define SUSP_SH_USTANDBY (1 << 3) /* SH-Mobile U-standby mode */ |
29 | #define SUSP_SH_SF (1 << 4) /* Enable self-refresh */ | 93 | #define SUSP_SH_SF (1 << 4) /* Enable self-refresh */ |
94 | #define SUSP_SH_MMU (1 << 5) /* Save/restore MMU and cache */ | ||
30 | 95 | ||
31 | #endif /* _ASM_SH_SUSPEND_H */ | 96 | #endif /* _ASM_SH_SUSPEND_H */ |
diff --git a/arch/sh/include/asm/system.h b/arch/sh/include/asm/system.h index b5c5acdc8c0e..c15415b4b169 100644 --- a/arch/sh/include/asm/system.h +++ b/arch/sh/include/asm/system.h | |||
@@ -171,10 +171,6 @@ BUILD_TRAP_HANDLER(fpu_error); | |||
171 | BUILD_TRAP_HANDLER(fpu_state_restore); | 171 | BUILD_TRAP_HANDLER(fpu_state_restore); |
172 | BUILD_TRAP_HANDLER(nmi); | 172 | BUILD_TRAP_HANDLER(nmi); |
173 | 173 | ||
174 | #ifdef CONFIG_BUG | ||
175 | extern void handle_BUG(struct pt_regs *); | ||
176 | #endif | ||
177 | |||
178 | #define arch_align_stack(x) (x) | 174 | #define arch_align_stack(x) (x) |
179 | 175 | ||
180 | struct mem_access { | 176 | struct mem_access { |
diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h index 607d413f6168..06814f5b59c7 100644 --- a/arch/sh/include/asm/system_32.h +++ b/arch/sh/include/asm/system_32.h | |||
@@ -232,4 +232,33 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5, | |||
232 | unsigned long r6, unsigned long r7, | 232 | unsigned long r6, unsigned long r7, |
233 | struct pt_regs __regs); | 233 | struct pt_regs __regs); |
234 | 234 | ||
235 | static inline void set_bl_bit(void) | ||
236 | { | ||
237 | unsigned long __dummy0, __dummy1; | ||
238 | |||
239 | __asm__ __volatile__ ( | ||
240 | "stc sr, %0\n\t" | ||
241 | "or %2, %0\n\t" | ||
242 | "and %3, %0\n\t" | ||
243 | "ldc %0, sr\n\t" | ||
244 | : "=&r" (__dummy0), "=r" (__dummy1) | ||
245 | : "r" (0x10000000), "r" (0xffffff0f) | ||
246 | : "memory" | ||
247 | ); | ||
248 | } | ||
249 | |||
250 | static inline void clear_bl_bit(void) | ||
251 | { | ||
252 | unsigned long __dummy0, __dummy1; | ||
253 | |||
254 | __asm__ __volatile__ ( | ||
255 | "stc sr, %0\n\t" | ||
256 | "and %2, %0\n\t" | ||
257 | "ldc %0, sr\n\t" | ||
258 | : "=&r" (__dummy0), "=r" (__dummy1) | ||
259 | : "1" (~0x10000000) | ||
260 | : "memory" | ||
261 | ); | ||
262 | } | ||
263 | |||
235 | #endif /* __ASM_SH_SYSTEM_32_H */ | 264 | #endif /* __ASM_SH_SYSTEM_32_H */ |
diff --git a/arch/sh/include/asm/system_64.h b/arch/sh/include/asm/system_64.h index 8e4a03e7966c..ab1dd917ea87 100644 --- a/arch/sh/include/asm/system_64.h +++ b/arch/sh/include/asm/system_64.h | |||
@@ -12,6 +12,7 @@ | |||
12 | * License. See the file "COPYING" in the main directory of this archive | 12 | * License. See the file "COPYING" in the main directory of this archive |
13 | * for more details. | 13 | * for more details. |
14 | */ | 14 | */ |
15 | #include <cpu/registers.h> | ||
15 | #include <asm/processor.h> | 16 | #include <asm/processor.h> |
16 | 17 | ||
17 | /* | 18 | /* |
@@ -47,4 +48,29 @@ static inline reg_size_t register_align(void *val) | |||
47 | return (unsigned long long)(signed long long)(signed long)val; | 48 | return (unsigned long long)(signed long long)(signed long)val; |
48 | } | 49 | } |
49 | 50 | ||
51 | #define SR_BL_LL 0x0000000010000000LL | ||
52 | |||
53 | static inline void set_bl_bit(void) | ||
54 | { | ||
55 | unsigned long long __dummy0, __dummy1 = SR_BL_LL; | ||
56 | |||
57 | __asm__ __volatile__("getcon " __SR ", %0\n\t" | ||
58 | "or %0, %1, %0\n\t" | ||
59 | "putcon %0, " __SR "\n\t" | ||
60 | : "=&r" (__dummy0) | ||
61 | : "r" (__dummy1)); | ||
62 | |||
63 | } | ||
64 | |||
65 | static inline void clear_bl_bit(void) | ||
66 | { | ||
67 | unsigned long long __dummy0, __dummy1 = ~SR_BL_LL; | ||
68 | |||
69 | __asm__ __volatile__("getcon " __SR ", %0\n\t" | ||
70 | "and %0, %1, %0\n\t" | ||
71 | "putcon %0, " __SR "\n\t" | ||
72 | : "=&r" (__dummy0) | ||
73 | : "r" (__dummy1)); | ||
74 | } | ||
75 | |||
50 | #endif /* __ASM_SH_SYSTEM_64_H */ | 76 | #endif /* __ASM_SH_SYSTEM_64_H */ |
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h index bdeb9d46d17d..1f3d927e2265 100644 --- a/arch/sh/include/asm/thread_info.h +++ b/arch/sh/include/asm/thread_info.h | |||
@@ -19,6 +19,7 @@ struct thread_info { | |||
19 | struct task_struct *task; /* main task structure */ | 19 | struct task_struct *task; /* main task structure */ |
20 | struct exec_domain *exec_domain; /* execution domain */ | 20 | struct exec_domain *exec_domain; /* execution domain */ |
21 | unsigned long flags; /* low level flags */ | 21 | unsigned long flags; /* low level flags */ |
22 | __u32 status; /* thread synchronous flags */ | ||
22 | __u32 cpu; | 23 | __u32 cpu; |
23 | int preempt_count; /* 0 => preemptable, <0 => BUG */ | 24 | int preempt_count; /* 0 => preemptable, <0 => BUG */ |
24 | mm_segment_t addr_limit; /* thread address space */ | 25 | mm_segment_t addr_limit; /* thread address space */ |
@@ -50,6 +51,7 @@ struct thread_info { | |||
50 | .task = &tsk, \ | 51 | .task = &tsk, \ |
51 | .exec_domain = &default_exec_domain, \ | 52 | .exec_domain = &default_exec_domain, \ |
52 | .flags = 0, \ | 53 | .flags = 0, \ |
54 | .status = 0, \ | ||
53 | .cpu = 0, \ | 55 | .cpu = 0, \ |
54 | .preempt_count = INIT_PREEMPT_COUNT, \ | 56 | .preempt_count = INIT_PREEMPT_COUNT, \ |
55 | .addr_limit = KERNEL_DS, \ | 57 | .addr_limit = KERNEL_DS, \ |
@@ -111,13 +113,11 @@ extern void free_thread_info(struct thread_info *ti); | |||
111 | #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ | 113 | #define TIF_SYSCALL_TRACE 0 /* syscall trace active */ |
112 | #define TIF_SIGPENDING 1 /* signal pending */ | 114 | #define TIF_SIGPENDING 1 /* signal pending */ |
113 | #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ | 115 | #define TIF_NEED_RESCHED 2 /* rescheduling necessary */ |
114 | #define TIF_RESTORE_SIGMASK 3 /* restore signal mask in do_signal() */ | ||
115 | #define TIF_SINGLESTEP 4 /* singlestepping active */ | 116 | #define TIF_SINGLESTEP 4 /* singlestepping active */ |
116 | #define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ | 117 | #define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ |
117 | #define TIF_SECCOMP 6 /* secure computing */ | 118 | #define TIF_SECCOMP 6 /* secure computing */ |
118 | #define TIF_NOTIFY_RESUME 7 /* callback before returning to user */ | 119 | #define TIF_NOTIFY_RESUME 7 /* callback before returning to user */ |
119 | #define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */ | 120 | #define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */ |
120 | #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ | ||
121 | #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ | 121 | #define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ |
122 | #define TIF_MEMDIE 18 | 122 | #define TIF_MEMDIE 18 |
123 | #define TIF_FREEZE 19 /* Freezing for suspend */ | 123 | #define TIF_FREEZE 19 /* Freezing for suspend */ |
@@ -125,13 +125,11 @@ extern void free_thread_info(struct thread_info *ti); | |||
125 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) | 125 | #define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) |
126 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) | 126 | #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) |
127 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) | 127 | #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) |
128 | #define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK) | ||
129 | #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) | 128 | #define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) |
130 | #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) | 129 | #define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) |
131 | #define _TIF_SECCOMP (1 << TIF_SECCOMP) | 130 | #define _TIF_SECCOMP (1 << TIF_SECCOMP) |
132 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) | 131 | #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) |
133 | #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) | 132 | #define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) |
134 | #define _TIF_USEDFPU (1 << TIF_USEDFPU) | ||
135 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) | 133 | #define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) |
136 | #define _TIF_FREEZE (1 << TIF_FREEZE) | 134 | #define _TIF_FREEZE (1 << TIF_FREEZE) |
137 | 135 | ||
@@ -149,13 +147,33 @@ extern void free_thread_info(struct thread_info *ti); | |||
149 | /* work to do on any return to u-space */ | 147 | /* work to do on any return to u-space */ |
150 | #define _TIF_ALLWORK_MASK (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING | \ | 148 | #define _TIF_ALLWORK_MASK (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING | \ |
151 | _TIF_NEED_RESCHED | _TIF_SYSCALL_AUDIT | \ | 149 | _TIF_NEED_RESCHED | _TIF_SYSCALL_AUDIT | \ |
152 | _TIF_SINGLESTEP | _TIF_RESTORE_SIGMASK | \ | 150 | _TIF_SINGLESTEP | _TIF_NOTIFY_RESUME | \ |
153 | _TIF_NOTIFY_RESUME | _TIF_SYSCALL_TRACEPOINT) | 151 | _TIF_SYSCALL_TRACEPOINT) |
154 | 152 | ||
155 | /* work to do on interrupt/exception return */ | 153 | /* work to do on interrupt/exception return */ |
156 | #define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \ | 154 | #define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \ |
157 | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP)) | 155 | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP)) |
158 | 156 | ||
157 | /* | ||
158 | * Thread-synchronous status. | ||
159 | * | ||
160 | * This is different from the flags in that nobody else | ||
161 | * ever touches our thread-synchronous status, so we don't | ||
162 | * have to worry about atomic accesses. | ||
163 | */ | ||
164 | #define TS_RESTORE_SIGMASK 0x0001 /* restore signal mask in do_signal() */ | ||
165 | #define TS_USEDFPU 0x0002 /* FPU used by this task this quantum */ | ||
166 | |||
167 | #ifndef __ASSEMBLY__ | ||
168 | #define HAVE_SET_RESTORE_SIGMASK 1 | ||
169 | static inline void set_restore_sigmask(void) | ||
170 | { | ||
171 | struct thread_info *ti = current_thread_info(); | ||
172 | ti->status |= TS_RESTORE_SIGMASK; | ||
173 | set_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags); | ||
174 | } | ||
175 | #endif /* !__ASSEMBLY__ */ | ||
176 | |||
159 | #endif /* __KERNEL__ */ | 177 | #endif /* __KERNEL__ */ |
160 | 178 | ||
161 | #endif /* __ASM_SH_THREAD_INFO_H */ | 179 | #endif /* __ASM_SH_THREAD_INFO_H */ |
diff --git a/arch/sh/include/asm/topology.h b/arch/sh/include/asm/topology.h index 65e7bd2f2240..37cdadd975ac 100644 --- a/arch/sh/include/asm/topology.h +++ b/arch/sh/include/asm/topology.h | |||
@@ -40,6 +40,14 @@ | |||
40 | 40 | ||
41 | #endif | 41 | #endif |
42 | 42 | ||
43 | #define mc_capable() (1) | ||
44 | |||
45 | const struct cpumask *cpu_coregroup_mask(unsigned int cpu); | ||
46 | |||
47 | extern cpumask_t cpu_core_map[NR_CPUS]; | ||
48 | |||
49 | #define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) | ||
50 | |||
43 | #include <asm-generic/topology.h> | 51 | #include <asm-generic/topology.h> |
44 | 52 | ||
45 | #endif /* _ASM_SH_TOPOLOGY_H */ | 53 | #endif /* _ASM_SH_TOPOLOGY_H */ |
diff --git a/arch/sh/include/asm/ubc.h b/arch/sh/include/asm/ubc.h index 4ca4b7717371..9bf961684431 100644 --- a/arch/sh/include/asm/ubc.h +++ b/arch/sh/include/asm/ubc.h | |||
@@ -60,16 +60,5 @@ | |||
60 | #define BRCR_UBDE (1 << 0) | 60 | #define BRCR_UBDE (1 << 0) |
61 | #endif | 61 | #endif |
62 | 62 | ||
63 | #ifndef __ASSEMBLY__ | ||
64 | /* arch/sh/kernel/cpu/ubc.S */ | ||
65 | extern void ubc_sleep(void); | ||
66 | |||
67 | #ifdef CONFIG_UBC_WAKEUP | ||
68 | extern void ubc_wakeup(void); | ||
69 | #else | ||
70 | #define ubc_wakeup() do { } while (0) | ||
71 | #endif | ||
72 | #endif | ||
73 | |||
74 | #endif /* __KERNEL__ */ | 63 | #endif /* __KERNEL__ */ |
75 | #endif /* __ASM_SH_UBC_H */ | 64 | #endif /* __ASM_SH_UBC_H */ |
diff --git a/arch/sh/include/asm/watchdog.h b/arch/sh/include/asm/watchdog.h index 2fe7cee9e43a..19dfff5c8511 100644 --- a/arch/sh/include/asm/watchdog.h +++ b/arch/sh/include/asm/watchdog.h | |||
@@ -2,6 +2,8 @@ | |||
2 | * include/asm-sh/watchdog.h | 2 | * include/asm-sh/watchdog.h |
3 | * | 3 | * |
4 | * Copyright (C) 2002, 2003 Paul Mundt | 4 | * Copyright (C) 2002, 2003 Paul Mundt |
5 | * Copyright (C) 2009 Siemens AG | ||
6 | * Copyright (C) 2009 Valentin Sitdikov | ||
5 | * | 7 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 8 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 9 | * under the terms of the GNU General Public License as published by the |
@@ -61,6 +63,61 @@ | |||
61 | #define WTCSR_CKS_2048 0x06 | 63 | #define WTCSR_CKS_2048 0x06 |
62 | #define WTCSR_CKS_4096 0x07 | 64 | #define WTCSR_CKS_4096 0x07 |
63 | 65 | ||
66 | #if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780) | ||
67 | /** | ||
68 | * sh_wdt_read_cnt - Read from Counter | ||
69 | * Reads back the WTCNT value. | ||
70 | */ | ||
71 | static inline __u32 sh_wdt_read_cnt(void) | ||
72 | { | ||
73 | return ctrl_inl(WTCNT_R); | ||
74 | } | ||
75 | |||
76 | /** | ||
77 | * sh_wdt_write_cnt - Write to Counter | ||
78 | * @val: Value to write | ||
79 | * | ||
80 | * Writes the given value @val to the lower byte of the timer counter. | ||
81 | * The upper byte is set manually on each write. | ||
82 | */ | ||
83 | static inline void sh_wdt_write_cnt(__u32 val) | ||
84 | { | ||
85 | ctrl_outl((WTCNT_HIGH << 24) | (__u32)val, WTCNT); | ||
86 | } | ||
87 | |||
88 | /** | ||
89 | * sh_wdt_write_bst - Write to Counter | ||
90 | * @val: Value to write | ||
91 | * | ||
92 | * Writes the given value @val to the lower byte of the timer counter. | ||
93 | * The upper byte is set manually on each write. | ||
94 | */ | ||
95 | static inline void sh_wdt_write_bst(__u32 val) | ||
96 | { | ||
97 | ctrl_outl((WTBST_HIGH << 24) | (__u32)val, WTBST); | ||
98 | } | ||
99 | /** | ||
100 | * sh_wdt_read_csr - Read from Control/Status Register | ||
101 | * | ||
102 | * Reads back the WTCSR value. | ||
103 | */ | ||
104 | static inline __u32 sh_wdt_read_csr(void) | ||
105 | { | ||
106 | return ctrl_inl(WTCSR_R); | ||
107 | } | ||
108 | |||
109 | /** | ||
110 | * sh_wdt_write_csr - Write to Control/Status Register | ||
111 | * @val: Value to write | ||
112 | * | ||
113 | * Writes the given value @val to the lower byte of the control/status | ||
114 | * register. The upper byte is set manually on each write. | ||
115 | */ | ||
116 | static inline void sh_wdt_write_csr(__u32 val) | ||
117 | { | ||
118 | ctrl_outl((WTCSR_HIGH << 24) | (__u32)val, WTCSR); | ||
119 | } | ||
120 | #else | ||
64 | /** | 121 | /** |
65 | * sh_wdt_read_cnt - Read from Counter | 122 | * sh_wdt_read_cnt - Read from Counter |
66 | * Reads back the WTCNT value. | 123 | * Reads back the WTCNT value. |
@@ -103,6 +160,6 @@ static inline void sh_wdt_write_csr(__u8 val) | |||
103 | { | 160 | { |
104 | ctrl_outw((WTCSR_HIGH << 8) | (__u16)val, WTCSR); | 161 | ctrl_outw((WTCSR_HIGH << 8) | (__u16)val, WTCSR); |
105 | } | 162 | } |
106 | 163 | #endif /* CONFIG_CPU_SUBTYPE_SH7785 || CONFIG_CPU_SUBTYPE_SH7780 */ | |
107 | #endif /* __KERNEL__ */ | 164 | #endif /* __KERNEL__ */ |
108 | #endif /* __ASM_SH_WATCHDOG_H */ | 165 | #endif /* __ASM_SH_WATCHDOG_H */ |
diff --git a/arch/sh/include/cpu-sh4/cpu/watchdog.h b/arch/sh/include/cpu-sh4/cpu/watchdog.h index 259f6a0ce23d..7672301d0c70 100644 --- a/arch/sh/include/cpu-sh4/cpu/watchdog.h +++ b/arch/sh/include/cpu-sh4/cpu/watchdog.h | |||
@@ -2,6 +2,8 @@ | |||
2 | * include/asm-sh/cpu-sh4/watchdog.h | 2 | * include/asm-sh/cpu-sh4/watchdog.h |
3 | * | 3 | * |
4 | * Copyright (C) 2002, 2003 Paul Mundt | 4 | * Copyright (C) 2002, 2003 Paul Mundt |
5 | * Copyright (C) 2009 Siemens AG | ||
6 | * Copyright (C) 2009 Sitdikov Valentin | ||
5 | * | 7 | * |
6 | * This file is subject to the terms and conditions of the GNU General Public | 8 | * This file is subject to the terms and conditions of the GNU General Public |
7 | * License. See the file "COPYING" in the main directory of this archive | 9 | * License. See the file "COPYING" in the main directory of this archive |
@@ -10,9 +12,20 @@ | |||
10 | #ifndef __ASM_CPU_SH4_WATCHDOG_H | 12 | #ifndef __ASM_CPU_SH4_WATCHDOG_H |
11 | #define __ASM_CPU_SH4_WATCHDOG_H | 13 | #define __ASM_CPU_SH4_WATCHDOG_H |
12 | 14 | ||
15 | #if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780) | ||
16 | /* Prefix definition */ | ||
17 | #define WTBST_HIGH 0x55 | ||
18 | /* Register definitions */ | ||
19 | #define WTCNT_R 0xffcc0010 /*WDTCNT*/ | ||
20 | #define WTCSR 0xffcc0004 /*WDTCSR*/ | ||
21 | #define WTCNT 0xffcc0000 /*WDTST*/ | ||
22 | #define WTST WTCNT | ||
23 | #define WTBST 0xffcc0008 /*WDTBST*/ | ||
24 | #else | ||
13 | /* Register definitions */ | 25 | /* Register definitions */ |
14 | #define WTCNT 0xffc00008 | 26 | #define WTCNT 0xffc00008 |
15 | #define WTCSR 0xffc0000c | 27 | #define WTCSR 0xffc0000c |
28 | #endif | ||
16 | 29 | ||
17 | /* Bit definitions */ | 30 | /* Bit definitions */ |
18 | #define WTCSR_TME 0x80 | 31 | #define WTCSR_TME 0x80 |
diff --git a/arch/sh/include/mach-common/mach/titan.h b/arch/sh/include/mach-common/mach/titan.h index 03f3583c8918..4a674d27cbb8 100644 --- a/arch/sh/include/mach-common/mach/titan.h +++ b/arch/sh/include/mach-common/mach/titan.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Platform defintions for Titan | 2 | * Platform definitions for Titan |
3 | */ | 3 | */ |
4 | #ifndef _ASM_SH_TITAN_H | 4 | #ifndef _ASM_SH_TITAN_H |
5 | #define _ASM_SH_TITAN_H | 5 | #define _ASM_SH_TITAN_H |
diff --git a/arch/sh/include/mach-ecovec24/mach/partner-jet-setup.txt b/arch/sh/include/mach-ecovec24/mach/partner-jet-setup.txt index 8b8e4fa1fee9..cc737b807334 100644 --- a/arch/sh/include/mach-ecovec24/mach/partner-jet-setup.txt +++ b/arch/sh/include/mach-ecovec24/mach/partner-jet-setup.txt | |||
@@ -22,13 +22,12 @@ ED 0xff000010, 0x00000004 | |||
22 | LIST "setup clocks" | 22 | LIST "setup clocks" |
23 | ED 0xa4150024, 0x00004000 | 23 | ED 0xa4150024, 0x00004000 |
24 | ED 0xa4150000, 0x8E003508 | 24 | ED 0xa4150000, 0x8E003508 |
25 | ED 0xa4150004, 0x00000000 | ||
26 | 25 | ||
27 | WAIT 1 | 26 | WAIT 1 |
28 | 27 | ||
29 | LIST "BSC" | 28 | LIST "BSC" |
30 | ED 0xff800020, 0xa5a50000 | 29 | ED 0xff800020, 0xa5a50000 |
31 | ED 0xfec10000, 0x00000013 | 30 | ED 0xfec10000, 0x00001013 |
32 | ED 0xfec10004, 0x11110400 | 31 | ED 0xfec10004, 0x11110400 |
33 | ED 0xfec10024, 0x00000440 | 32 | ED 0xfec10024, 0x00000440 |
34 | 33 | ||
diff --git a/arch/sh/include/mach-se/mach/se7722.h b/arch/sh/include/mach-se/mach/se7722.h index e971d9a82f4a..16505bfb8a9e 100644 --- a/arch/sh/include/mach-se/mach/se7722.h +++ b/arch/sh/include/mach-se/mach/se7722.h | |||
@@ -92,18 +92,11 @@ | |||
92 | #define SE7722_FPGA_IRQ_MRSHPC1 3 /* IRQ1 */ | 92 | #define SE7722_FPGA_IRQ_MRSHPC1 3 /* IRQ1 */ |
93 | #define SE7722_FPGA_IRQ_MRSHPC2 4 /* IRQ1 */ | 93 | #define SE7722_FPGA_IRQ_MRSHPC2 4 /* IRQ1 */ |
94 | #define SE7722_FPGA_IRQ_MRSHPC3 5 /* IRQ1 */ | 94 | #define SE7722_FPGA_IRQ_MRSHPC3 5 /* IRQ1 */ |
95 | |||
96 | #define SE7722_FPGA_IRQ_NR 6 | 95 | #define SE7722_FPGA_IRQ_NR 6 |
97 | #define SE7722_FPGA_IRQ_BASE 110 | ||
98 | |||
99 | #define MRSHPC_IRQ3 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC3) | ||
100 | #define MRSHPC_IRQ2 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC2) | ||
101 | #define MRSHPC_IRQ1 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC1) | ||
102 | #define MRSHPC_IRQ0 (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_MRSHPC0) | ||
103 | #define SMC_IRQ (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_SMC) | ||
104 | #define USB_IRQ (SE7722_FPGA_IRQ_BASE + SE7722_FPGA_IRQ_USB) | ||
105 | 96 | ||
106 | /* arch/sh/boards/se/7722/irq.c */ | 97 | /* arch/sh/boards/se/7722/irq.c */ |
98 | extern unsigned int se7722_fpga_irq[]; | ||
99 | |||
107 | void init_se7722_IRQ(void); | 100 | void init_se7722_IRQ(void); |
108 | 101 | ||
109 | #define __IO_PREFIX se7722 | 102 | #define __IO_PREFIX se7722 |
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile index a2d0a40f3848..0471a3eb25ed 100644 --- a/arch/sh/kernel/Makefile +++ b/arch/sh/kernel/Makefile | |||
@@ -9,8 +9,12 @@ ifdef CONFIG_FUNCTION_TRACER | |||
9 | CFLAGS_REMOVE_ftrace.o = -pg | 9 | CFLAGS_REMOVE_ftrace.o = -pg |
10 | endif | 10 | endif |
11 | 11 | ||
12 | obj-y := debugtraps.o dumpstack.o idle.o io.o io_generic.o irq.o \ | 12 | CFLAGS_REMOVE_return_address.o = -pg |
13 | machvec.o nmi_debug.o process_$(BITS).o ptrace_$(BITS).o \ | 13 | |
14 | obj-y := debugtraps.o dma-nommu.o dumpstack.o \ | ||
15 | idle.o io.o io_generic.o irq.o \ | ||
16 | irq_$(BITS).o machvec.o nmi_debug.o process_$(BITS).o \ | ||
17 | ptrace_$(BITS).o return_address.o \ | ||
14 | setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ | 18 | setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o \ |
15 | syscalls_$(BITS).o time.o topology.o traps.o \ | 19 | syscalls_$(BITS).o time.o topology.o traps.o \ |
16 | traps_$(BITS).o unwinder.o | 20 | traps_$(BITS).o unwinder.o |
@@ -28,13 +32,13 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | |||
28 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 32 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
29 | obj-$(CONFIG_IO_TRAPPED) += io_trapped.o | 33 | obj-$(CONFIG_IO_TRAPPED) += io_trapped.o |
30 | obj-$(CONFIG_KPROBES) += kprobes.o | 34 | obj-$(CONFIG_KPROBES) += kprobes.o |
31 | obj-$(CONFIG_GENERIC_GPIO) += gpio.o | ||
32 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 35 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
33 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o | 36 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o |
34 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 37 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
35 | obj-$(CONFIG_DUMP_CODE) += disassemble.o | 38 | obj-$(CONFIG_DUMP_CODE) += disassemble.o |
36 | obj-$(CONFIG_HIBERNATION) += swsusp.o | 39 | obj-$(CONFIG_HIBERNATION) += swsusp.o |
37 | obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o | 40 | obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o |
41 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o | ||
38 | 42 | ||
39 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o | 43 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o |
40 | 44 | ||
diff --git a/arch/sh/kernel/asm-offsets.c b/arch/sh/kernel/asm-offsets.c index d218e808294e..08a2be775b6c 100644 --- a/arch/sh/kernel/asm-offsets.c +++ b/arch/sh/kernel/asm-offsets.c | |||
@@ -34,5 +34,28 @@ int main(void) | |||
34 | DEFINE(PBE_NEXT, offsetof(struct pbe, next)); | 34 | DEFINE(PBE_NEXT, offsetof(struct pbe, next)); |
35 | DEFINE(SWSUSP_ARCH_REGS_SIZE, sizeof(struct swsusp_arch_regs)); | 35 | DEFINE(SWSUSP_ARCH_REGS_SIZE, sizeof(struct swsusp_arch_regs)); |
36 | #endif | 36 | #endif |
37 | |||
38 | DEFINE(SH_SLEEP_MODE, offsetof(struct sh_sleep_data, mode)); | ||
39 | DEFINE(SH_SLEEP_SF_PRE, offsetof(struct sh_sleep_data, sf_pre)); | ||
40 | DEFINE(SH_SLEEP_SF_POST, offsetof(struct sh_sleep_data, sf_post)); | ||
41 | DEFINE(SH_SLEEP_RESUME, offsetof(struct sh_sleep_data, resume)); | ||
42 | DEFINE(SH_SLEEP_VBR, offsetof(struct sh_sleep_data, vbr)); | ||
43 | DEFINE(SH_SLEEP_SPC, offsetof(struct sh_sleep_data, spc)); | ||
44 | DEFINE(SH_SLEEP_SR, offsetof(struct sh_sleep_data, sr)); | ||
45 | DEFINE(SH_SLEEP_SP, offsetof(struct sh_sleep_data, sp)); | ||
46 | DEFINE(SH_SLEEP_BASE_ADDR, offsetof(struct sh_sleep_data, addr)); | ||
47 | DEFINE(SH_SLEEP_BASE_DATA, offsetof(struct sh_sleep_data, data)); | ||
48 | DEFINE(SH_SLEEP_REG_STBCR, offsetof(struct sh_sleep_regs, stbcr)); | ||
49 | DEFINE(SH_SLEEP_REG_BAR, offsetof(struct sh_sleep_regs, bar)); | ||
50 | DEFINE(SH_SLEEP_REG_PTEH, offsetof(struct sh_sleep_regs, pteh)); | ||
51 | DEFINE(SH_SLEEP_REG_PTEL, offsetof(struct sh_sleep_regs, ptel)); | ||
52 | DEFINE(SH_SLEEP_REG_TTB, offsetof(struct sh_sleep_regs, ttb)); | ||
53 | DEFINE(SH_SLEEP_REG_TEA, offsetof(struct sh_sleep_regs, tea)); | ||
54 | DEFINE(SH_SLEEP_REG_MMUCR, offsetof(struct sh_sleep_regs, mmucr)); | ||
55 | DEFINE(SH_SLEEP_REG_PTEA, offsetof(struct sh_sleep_regs, ptea)); | ||
56 | DEFINE(SH_SLEEP_REG_PASCR, offsetof(struct sh_sleep_regs, pascr)); | ||
57 | DEFINE(SH_SLEEP_REG_IRMCR, offsetof(struct sh_sleep_regs, irmcr)); | ||
58 | DEFINE(SH_SLEEP_REG_CCR, offsetof(struct sh_sleep_regs, ccr)); | ||
59 | DEFINE(SH_SLEEP_REG_RAMCR, offsetof(struct sh_sleep_regs, ramcr)); | ||
37 | return 0; | 60 | return 0; |
38 | } | 61 | } |
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile index 3d6b9312dc47..d97c803719ec 100644 --- a/arch/sh/kernel/cpu/Makefile +++ b/arch/sh/kernel/cpu/Makefile | |||
@@ -15,7 +15,6 @@ obj-$(CONFIG_ARCH_SHMOBILE) += shmobile/ | |||
15 | 15 | ||
16 | # Common interfaces. | 16 | # Common interfaces. |
17 | 17 | ||
18 | obj-$(CONFIG_UBC_WAKEUP) += ubc.o | ||
19 | obj-$(CONFIG_SH_ADC) += adc.o | 18 | obj-$(CONFIG_SH_ADC) += adc.o |
20 | obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o | 19 | obj-$(CONFIG_SH_CLK_CPG) += clock-cpg.o |
21 | 20 | ||
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index e932ebef4738..89b4b76c0d76 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c | |||
@@ -75,16 +75,11 @@ static void __init expmask_init(void) | |||
75 | /* | 75 | /* |
76 | * Future proofing. | 76 | * Future proofing. |
77 | * | 77 | * |
78 | * Disable support for slottable sleep instruction | 78 | * Disable support for slottable sleep instruction, non-nop |
79 | * and non-nop instructions in the rte delay slot. | 79 | * instructions in the rte delay slot, and associative writes to |
80 | * the memory-mapped cache array. | ||
80 | */ | 81 | */ |
81 | expmask &= ~(EXPMASK_RTEDS | EXPMASK_BRDSSLP); | 82 | expmask &= ~(EXPMASK_RTEDS | EXPMASK_BRDSSLP | EXPMASK_MMCAW); |
82 | |||
83 | /* | ||
84 | * Enable associative writes to the memory-mapped cache array | ||
85 | * until the cache flush ops have been rewritten. | ||
86 | */ | ||
87 | expmask |= EXPMASK_MMCAW; | ||
88 | 83 | ||
89 | __raw_writel(expmask, EXPMASK); | 84 | __raw_writel(expmask, EXPMASK); |
90 | ctrl_barrier(); | 85 | ctrl_barrier(); |
@@ -311,12 +306,12 @@ asmlinkage void __init sh_cpu_init(void) | |||
311 | if (fpu_disabled) { | 306 | if (fpu_disabled) { |
312 | printk("FPU Disabled\n"); | 307 | printk("FPU Disabled\n"); |
313 | current_cpu_data.flags &= ~CPU_HAS_FPU; | 308 | current_cpu_data.flags &= ~CPU_HAS_FPU; |
314 | disable_fpu(); | ||
315 | } | 309 | } |
316 | 310 | ||
317 | /* FPU initialization */ | 311 | /* FPU initialization */ |
312 | disable_fpu(); | ||
318 | if ((current_cpu_data.flags & CPU_HAS_FPU)) { | 313 | if ((current_cpu_data.flags & CPU_HAS_FPU)) { |
319 | clear_thread_flag(TIF_USEDFPU); | 314 | current_thread_info()->status &= ~TS_USEDFPU; |
320 | clear_used_math(); | 315 | clear_used_math(); |
321 | } | 316 | } |
322 | 317 | ||
@@ -338,17 +333,6 @@ asmlinkage void __init sh_cpu_init(void) | |||
338 | } | 333 | } |
339 | #endif | 334 | #endif |
340 | 335 | ||
341 | /* | ||
342 | * Some brain-damaged loaders decided it would be a good idea to put | ||
343 | * the UBC to sleep. This causes some issues when it comes to things | ||
344 | * like PTRACE_SINGLESTEP or doing hardware watchpoints in GDB. So .. | ||
345 | * we wake it up and hope that all is well. | ||
346 | */ | ||
347 | #ifdef CONFIG_SUPERH32 | ||
348 | if (raw_smp_processor_id() == 0) | ||
349 | ubc_wakeup(); | ||
350 | #endif | ||
351 | |||
352 | speculative_execution_init(); | 336 | speculative_execution_init(); |
353 | expmask_init(); | 337 | expmask_init(); |
354 | } | 338 | } |
diff --git a/arch/sh/kernel/cpu/sh2a/fpu.c b/arch/sh/kernel/cpu/sh2a/fpu.c index 6df2fb98eb30..d395ce5740e7 100644 --- a/arch/sh/kernel/cpu/sh2a/fpu.c +++ b/arch/sh/kernel/cpu/sh2a/fpu.c | |||
@@ -25,14 +25,12 @@ | |||
25 | 25 | ||
26 | /* | 26 | /* |
27 | * Save FPU registers onto task structure. | 27 | * Save FPU registers onto task structure. |
28 | * Assume called with FPU enabled (SR.FD=0). | ||
29 | */ | 28 | */ |
30 | void | 29 | void |
31 | save_fpu(struct task_struct *tsk, struct pt_regs *regs) | 30 | save_fpu(struct task_struct *tsk) |
32 | { | 31 | { |
33 | unsigned long dummy; | 32 | unsigned long dummy; |
34 | 33 | ||
35 | clear_tsk_thread_flag(tsk, TIF_USEDFPU); | ||
36 | enable_fpu(); | 34 | enable_fpu(); |
37 | asm volatile("sts.l fpul, @-%0\n\t" | 35 | asm volatile("sts.l fpul, @-%0\n\t" |
38 | "sts.l fpscr, @-%0\n\t" | 36 | "sts.l fpscr, @-%0\n\t" |
@@ -60,7 +58,6 @@ save_fpu(struct task_struct *tsk, struct pt_regs *regs) | |||
60 | : "memory"); | 58 | : "memory"); |
61 | 59 | ||
62 | disable_fpu(); | 60 | disable_fpu(); |
63 | release_fpu(regs); | ||
64 | } | 61 | } |
65 | 62 | ||
66 | static void | 63 | static void |
@@ -598,31 +595,31 @@ BUILD_TRAP_HANDLER(fpu_error) | |||
598 | struct task_struct *tsk = current; | 595 | struct task_struct *tsk = current; |
599 | TRAP_HANDLER_DECL; | 596 | TRAP_HANDLER_DECL; |
600 | 597 | ||
601 | save_fpu(tsk, regs); | 598 | __unlazy_fpu(tsk, regs); |
602 | if (ieee_fpe_handler(regs)) { | 599 | if (ieee_fpe_handler(regs)) { |
603 | tsk->thread.fpu.hard.fpscr &= | 600 | tsk->thread.fpu.hard.fpscr &= |
604 | ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); | 601 | ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); |
605 | grab_fpu(regs); | 602 | grab_fpu(regs); |
606 | restore_fpu(tsk); | 603 | restore_fpu(tsk); |
607 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 604 | task_thread_info(tsk)->status |= TS_USEDFPU; |
608 | return; | 605 | return; |
609 | } | 606 | } |
610 | 607 | ||
611 | force_sig(SIGFPE, tsk); | 608 | force_sig(SIGFPE, tsk); |
612 | } | 609 | } |
613 | 610 | ||
614 | BUILD_TRAP_HANDLER(fpu_state_restore) | 611 | void fpu_state_restore(struct pt_regs *regs) |
615 | { | 612 | { |
616 | struct task_struct *tsk = current; | 613 | struct task_struct *tsk = current; |
617 | TRAP_HANDLER_DECL; | ||
618 | 614 | ||
619 | grab_fpu(regs); | 615 | grab_fpu(regs); |
620 | if (!user_mode(regs)) { | 616 | if (unlikely(!user_mode(regs))) { |
621 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); | 617 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); |
618 | BUG(); | ||
622 | return; | 619 | return; |
623 | } | 620 | } |
624 | 621 | ||
625 | if (used_math()) { | 622 | if (likely(used_math())) { |
626 | /* Using the FPU again. */ | 623 | /* Using the FPU again. */ |
627 | restore_fpu(tsk); | 624 | restore_fpu(tsk); |
628 | } else { | 625 | } else { |
@@ -630,5 +627,13 @@ BUILD_TRAP_HANDLER(fpu_state_restore) | |||
630 | fpu_init(); | 627 | fpu_init(); |
631 | set_used_math(); | 628 | set_used_math(); |
632 | } | 629 | } |
633 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 630 | task_thread_info(tsk)->status |= TS_USEDFPU; |
631 | tsk->fpu_counter++; | ||
632 | } | ||
633 | |||
634 | BUILD_TRAP_HANDLER(fpu_state_restore) | ||
635 | { | ||
636 | TRAP_HANDLER_DECL; | ||
637 | |||
638 | fpu_state_restore(regs); | ||
634 | } | 639 | } |
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index bb407ef0b91e..3f7e2a22c7c2 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S | |||
@@ -297,41 +297,8 @@ ENTRY(vbr_base) | |||
297 | ! | 297 | ! |
298 | .balign 256,0,256 | 298 | .balign 256,0,256 |
299 | general_exception: | 299 | general_exception: |
300 | #ifndef CONFIG_CPU_SUBTYPE_SHX3 | ||
301 | bra handle_exception | 300 | bra handle_exception |
302 | sts pr, k3 ! save original pr value in k3 | 301 | sts pr, k3 ! save original pr value in k3 |
303 | #else | ||
304 | mov.l 1f, k4 | ||
305 | mov.l @k4, k4 | ||
306 | |||
307 | ! Is EXPEVT larger than 0x800? | ||
308 | mov #0x8, k0 | ||
309 | shll8 k0 | ||
310 | cmp/hs k0, k4 | ||
311 | bf 0f | ||
312 | |||
313 | ! then add 0x580 (k2 is 0xd80 or 0xda0) | ||
314 | mov #0x58, k0 | ||
315 | shll2 k0 | ||
316 | shll2 k0 | ||
317 | add k0, k4 | ||
318 | 0: | ||
319 | ! Setup stack and save DSP context (k0 contains original r15 on return) | ||
320 | bsr prepare_stack | ||
321 | nop | ||
322 | |||
323 | ! Save registers / Switch to bank 0 | ||
324 | mov k4, k2 ! keep vector in k2 | ||
325 | mov.l 1f, k4 ! SR bits to clear in k4 | ||
326 | bsr save_regs ! needs original pr value in k3 | ||
327 | nop | ||
328 | |||
329 | bra handle_exception_special | ||
330 | nop | ||
331 | |||
332 | .align 2 | ||
333 | 1: .long EXPEVT | ||
334 | #endif | ||
335 | 302 | ||
336 | ! prepare_stack() | 303 | ! prepare_stack() |
337 | ! - roll back gRB | 304 | ! - roll back gRB |
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile index 203b18347b83..3a1dbc709831 100644 --- a/arch/sh/kernel/cpu/sh4/Makefile +++ b/arch/sh/kernel/cpu/sh4/Makefile | |||
@@ -9,6 +9,11 @@ obj-$(CONFIG_HIBERNATION) += $(addprefix ../sh3/, swsusp.o) | |||
9 | obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o | 9 | obj-$(CONFIG_SH_FPU) += fpu.o softfloat.o |
10 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o | 10 | obj-$(CONFIG_SH_STORE_QUEUES) += sq.o |
11 | 11 | ||
12 | # Perf events | ||
13 | perf-$(CONFIG_CPU_SUBTYPE_SH7750) := perf_event.o | ||
14 | perf-$(CONFIG_CPU_SUBTYPE_SH7750S) := perf_event.o | ||
15 | perf-$(CONFIG_CPU_SUBTYPE_SH7091) := perf_event.o | ||
16 | |||
12 | # CPU subtype setup | 17 | # CPU subtype setup |
13 | obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o | 18 | obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o |
14 | obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o | 19 | obj-$(CONFIG_CPU_SUBTYPE_SH7750R) += setup-sh7750.o |
@@ -27,4 +32,5 @@ endif | |||
27 | # Additional clocks by subtype | 32 | # Additional clocks by subtype |
28 | clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o | 33 | clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o |
29 | 34 | ||
30 | obj-y += $(clock-y) | 35 | obj-y += $(clock-y) |
36 | obj-$(CONFIG_PERF_EVENTS) += $(perf-y) | ||
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c index e3ea5411da6d..e97857aec8a0 100644 --- a/arch/sh/kernel/cpu/sh4/fpu.c +++ b/arch/sh/kernel/cpu/sh4/fpu.c | |||
@@ -41,13 +41,11 @@ static unsigned int fpu_exception_flags; | |||
41 | 41 | ||
42 | /* | 42 | /* |
43 | * Save FPU registers onto task structure. | 43 | * Save FPU registers onto task structure. |
44 | * Assume called with FPU enabled (SR.FD=0). | ||
45 | */ | 44 | */ |
46 | void save_fpu(struct task_struct *tsk, struct pt_regs *regs) | 45 | void save_fpu(struct task_struct *tsk) |
47 | { | 46 | { |
48 | unsigned long dummy; | 47 | unsigned long dummy; |
49 | 48 | ||
50 | clear_tsk_thread_flag(tsk, TIF_USEDFPU); | ||
51 | enable_fpu(); | 49 | enable_fpu(); |
52 | asm volatile ("sts.l fpul, @-%0\n\t" | 50 | asm volatile ("sts.l fpul, @-%0\n\t" |
53 | "sts.l fpscr, @-%0\n\t" | 51 | "sts.l fpscr, @-%0\n\t" |
@@ -92,7 +90,6 @@ void save_fpu(struct task_struct *tsk, struct pt_regs *regs) | |||
92 | :"memory"); | 90 | :"memory"); |
93 | 91 | ||
94 | disable_fpu(); | 92 | disable_fpu(); |
95 | release_fpu(regs); | ||
96 | } | 93 | } |
97 | 94 | ||
98 | static void restore_fpu(struct task_struct *tsk) | 95 | static void restore_fpu(struct task_struct *tsk) |
@@ -285,7 +282,6 @@ static int ieee_fpe_handler(struct pt_regs *regs) | |||
285 | /* fcnvsd */ | 282 | /* fcnvsd */ |
286 | struct task_struct *tsk = current; | 283 | struct task_struct *tsk = current; |
287 | 284 | ||
288 | save_fpu(tsk, regs); | ||
289 | if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR)) | 285 | if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR)) |
290 | /* FPU error */ | 286 | /* FPU error */ |
291 | denormal_to_double(&tsk->thread.fpu.hard, | 287 | denormal_to_double(&tsk->thread.fpu.hard, |
@@ -462,7 +458,7 @@ BUILD_TRAP_HANDLER(fpu_error) | |||
462 | struct task_struct *tsk = current; | 458 | struct task_struct *tsk = current; |
463 | TRAP_HANDLER_DECL; | 459 | TRAP_HANDLER_DECL; |
464 | 460 | ||
465 | save_fpu(tsk, regs); | 461 | __unlazy_fpu(tsk, regs); |
466 | fpu_exception_flags = 0; | 462 | fpu_exception_flags = 0; |
467 | if (ieee_fpe_handler(regs)) { | 463 | if (ieee_fpe_handler(regs)) { |
468 | tsk->thread.fpu.hard.fpscr &= | 464 | tsk->thread.fpu.hard.fpscr &= |
@@ -473,7 +469,7 @@ BUILD_TRAP_HANDLER(fpu_error) | |||
473 | tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10); | 469 | tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10); |
474 | grab_fpu(regs); | 470 | grab_fpu(regs); |
475 | restore_fpu(tsk); | 471 | restore_fpu(tsk); |
476 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 472 | task_thread_info(tsk)->status |= TS_USEDFPU; |
477 | if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) & | 473 | if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) & |
478 | (fpu_exception_flags >> 2)) == 0) { | 474 | (fpu_exception_flags >> 2)) == 0) { |
479 | return; | 475 | return; |
@@ -483,18 +479,18 @@ BUILD_TRAP_HANDLER(fpu_error) | |||
483 | force_sig(SIGFPE, tsk); | 479 | force_sig(SIGFPE, tsk); |
484 | } | 480 | } |
485 | 481 | ||
486 | BUILD_TRAP_HANDLER(fpu_state_restore) | 482 | void fpu_state_restore(struct pt_regs *regs) |
487 | { | 483 | { |
488 | struct task_struct *tsk = current; | 484 | struct task_struct *tsk = current; |
489 | TRAP_HANDLER_DECL; | ||
490 | 485 | ||
491 | grab_fpu(regs); | 486 | grab_fpu(regs); |
492 | if (!user_mode(regs)) { | 487 | if (unlikely(!user_mode(regs))) { |
493 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); | 488 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); |
489 | BUG(); | ||
494 | return; | 490 | return; |
495 | } | 491 | } |
496 | 492 | ||
497 | if (used_math()) { | 493 | if (likely(used_math())) { |
498 | /* Using the FPU again. */ | 494 | /* Using the FPU again. */ |
499 | restore_fpu(tsk); | 495 | restore_fpu(tsk); |
500 | } else { | 496 | } else { |
@@ -502,5 +498,13 @@ BUILD_TRAP_HANDLER(fpu_state_restore) | |||
502 | fpu_init(); | 498 | fpu_init(); |
503 | set_used_math(); | 499 | set_used_math(); |
504 | } | 500 | } |
505 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 501 | task_thread_info(tsk)->status |= TS_USEDFPU; |
502 | tsk->fpu_counter++; | ||
503 | } | ||
504 | |||
505 | BUILD_TRAP_HANDLER(fpu_state_restore) | ||
506 | { | ||
507 | TRAP_HANDLER_DECL; | ||
508 | |||
509 | fpu_state_restore(regs); | ||
506 | } | 510 | } |
diff --git a/arch/sh/kernel/cpu/sh4/perf_event.c b/arch/sh/kernel/cpu/sh4/perf_event.c new file mode 100644 index 000000000000..7f9ecc9c2d02 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4/perf_event.c | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * Performance events support for SH7750-style performance counters | ||
3 | * | ||
4 | * Copyright (C) 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/irq.h> | ||
14 | #include <linux/perf_event.h> | ||
15 | #include <asm/processor.h> | ||
16 | |||
17 | #define PM_CR_BASE 0xff000084 /* 16-bit */ | ||
18 | #define PM_CTR_BASE 0xff100004 /* 32-bit */ | ||
19 | |||
20 | #define PMCR(n) (PM_CR_BASE + ((n) * 0x04)) | ||
21 | #define PMCTRH(n) (PM_CTR_BASE + 0x00 + ((n) * 0x08)) | ||
22 | #define PMCTRL(n) (PM_CTR_BASE + 0x04 + ((n) * 0x08)) | ||
23 | |||
24 | #define PMCR_PMM_MASK 0x0000003f | ||
25 | |||
26 | #define PMCR_CLKF 0x00000100 | ||
27 | #define PMCR_PMCLR 0x00002000 | ||
28 | #define PMCR_PMST 0x00004000 | ||
29 | #define PMCR_PMEN 0x00008000 | ||
30 | |||
31 | static struct sh_pmu sh7750_pmu; | ||
32 | |||
33 | /* | ||
34 | * There are a number of events supported by each counter (33 in total). | ||
35 | * Since we have 2 counters, each counter will take the event code as it | ||
36 | * corresponds to the PMCR PMM setting. Each counter can be configured | ||
37 | * independently. | ||
38 | * | ||
39 | * Event Code Description | ||
40 | * ---------- ----------- | ||
41 | * | ||
42 | * 0x01 Operand read access | ||
43 | * 0x02 Operand write access | ||
44 | * 0x03 UTLB miss | ||
45 | * 0x04 Operand cache read miss | ||
46 | * 0x05 Operand cache write miss | ||
47 | * 0x06 Instruction fetch (w/ cache) | ||
48 | * 0x07 Instruction TLB miss | ||
49 | * 0x08 Instruction cache miss | ||
50 | * 0x09 All operand accesses | ||
51 | * 0x0a All instruction accesses | ||
52 | * 0x0b OC RAM operand access | ||
53 | * 0x0d On-chip I/O space access | ||
54 | * 0x0e Operand access (r/w) | ||
55 | * 0x0f Operand cache miss (r/w) | ||
56 | * 0x10 Branch instruction | ||
57 | * 0x11 Branch taken | ||
58 | * 0x12 BSR/BSRF/JSR | ||
59 | * 0x13 Instruction execution | ||
60 | * 0x14 Instruction execution in parallel | ||
61 | * 0x15 FPU Instruction execution | ||
62 | * 0x16 Interrupt | ||
63 | * 0x17 NMI | ||
64 | * 0x18 trapa instruction execution | ||
65 | * 0x19 UBCA match | ||
66 | * 0x1a UBCB match | ||
67 | * 0x21 Instruction cache fill | ||
68 | * 0x22 Operand cache fill | ||
69 | * 0x23 Elapsed time | ||
70 | * 0x24 Pipeline freeze by I-cache miss | ||
71 | * 0x25 Pipeline freeze by D-cache miss | ||
72 | * 0x27 Pipeline freeze by branch instruction | ||
73 | * 0x28 Pipeline freeze by CPU register | ||
74 | * 0x29 Pipeline freeze by FPU | ||
75 | */ | ||
76 | |||
77 | static const int sh7750_general_events[] = { | ||
78 | [PERF_COUNT_HW_CPU_CYCLES] = 0x0023, | ||
79 | [PERF_COUNT_HW_INSTRUCTIONS] = 0x000a, | ||
80 | [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0006, /* I-cache */ | ||
81 | [PERF_COUNT_HW_CACHE_MISSES] = 0x0008, /* I-cache */ | ||
82 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0010, | ||
83 | [PERF_COUNT_HW_BRANCH_MISSES] = -1, | ||
84 | [PERF_COUNT_HW_BUS_CYCLES] = -1, | ||
85 | }; | ||
86 | |||
87 | #define C(x) PERF_COUNT_HW_CACHE_##x | ||
88 | |||
89 | static const int sh7750_cache_events | ||
90 | [PERF_COUNT_HW_CACHE_MAX] | ||
91 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
92 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = | ||
93 | { | ||
94 | [ C(L1D) ] = { | ||
95 | [ C(OP_READ) ] = { | ||
96 | [ C(RESULT_ACCESS) ] = 0x0001, | ||
97 | [ C(RESULT_MISS) ] = 0x0004, | ||
98 | }, | ||
99 | [ C(OP_WRITE) ] = { | ||
100 | [ C(RESULT_ACCESS) ] = 0x0002, | ||
101 | [ C(RESULT_MISS) ] = 0x0005, | ||
102 | }, | ||
103 | [ C(OP_PREFETCH) ] = { | ||
104 | [ C(RESULT_ACCESS) ] = 0, | ||
105 | [ C(RESULT_MISS) ] = 0, | ||
106 | }, | ||
107 | }, | ||
108 | |||
109 | [ C(L1I) ] = { | ||
110 | [ C(OP_READ) ] = { | ||
111 | [ C(RESULT_ACCESS) ] = 0x0006, | ||
112 | [ C(RESULT_MISS) ] = 0x0008, | ||
113 | }, | ||
114 | [ C(OP_WRITE) ] = { | ||
115 | [ C(RESULT_ACCESS) ] = -1, | ||
116 | [ C(RESULT_MISS) ] = -1, | ||
117 | }, | ||
118 | [ C(OP_PREFETCH) ] = { | ||
119 | [ C(RESULT_ACCESS) ] = 0, | ||
120 | [ C(RESULT_MISS) ] = 0, | ||
121 | }, | ||
122 | }, | ||
123 | |||
124 | [ C(LL) ] = { | ||
125 | [ C(OP_READ) ] = { | ||
126 | [ C(RESULT_ACCESS) ] = 0, | ||
127 | [ C(RESULT_MISS) ] = 0, | ||
128 | }, | ||
129 | [ C(OP_WRITE) ] = { | ||
130 | [ C(RESULT_ACCESS) ] = 0, | ||
131 | [ C(RESULT_MISS) ] = 0, | ||
132 | }, | ||
133 | [ C(OP_PREFETCH) ] = { | ||
134 | [ C(RESULT_ACCESS) ] = 0, | ||
135 | [ C(RESULT_MISS) ] = 0, | ||
136 | }, | ||
137 | }, | ||
138 | |||
139 | [ C(DTLB) ] = { | ||
140 | [ C(OP_READ) ] = { | ||
141 | [ C(RESULT_ACCESS) ] = 0, | ||
142 | [ C(RESULT_MISS) ] = 0x0003, | ||
143 | }, | ||
144 | [ C(OP_WRITE) ] = { | ||
145 | [ C(RESULT_ACCESS) ] = 0, | ||
146 | [ C(RESULT_MISS) ] = 0, | ||
147 | }, | ||
148 | [ C(OP_PREFETCH) ] = { | ||
149 | [ C(RESULT_ACCESS) ] = 0, | ||
150 | [ C(RESULT_MISS) ] = 0, | ||
151 | }, | ||
152 | }, | ||
153 | |||
154 | [ C(ITLB) ] = { | ||
155 | [ C(OP_READ) ] = { | ||
156 | [ C(RESULT_ACCESS) ] = 0, | ||
157 | [ C(RESULT_MISS) ] = 0x0007, | ||
158 | }, | ||
159 | [ C(OP_WRITE) ] = { | ||
160 | [ C(RESULT_ACCESS) ] = -1, | ||
161 | [ C(RESULT_MISS) ] = -1, | ||
162 | }, | ||
163 | [ C(OP_PREFETCH) ] = { | ||
164 | [ C(RESULT_ACCESS) ] = -1, | ||
165 | [ C(RESULT_MISS) ] = -1, | ||
166 | }, | ||
167 | }, | ||
168 | |||
169 | [ C(BPU) ] = { | ||
170 | [ C(OP_READ) ] = { | ||
171 | [ C(RESULT_ACCESS) ] = -1, | ||
172 | [ C(RESULT_MISS) ] = -1, | ||
173 | }, | ||
174 | [ C(OP_WRITE) ] = { | ||
175 | [ C(RESULT_ACCESS) ] = -1, | ||
176 | [ C(RESULT_MISS) ] = -1, | ||
177 | }, | ||
178 | [ C(OP_PREFETCH) ] = { | ||
179 | [ C(RESULT_ACCESS) ] = -1, | ||
180 | [ C(RESULT_MISS) ] = -1, | ||
181 | }, | ||
182 | }, | ||
183 | }; | ||
184 | |||
185 | static int sh7750_event_map(int event) | ||
186 | { | ||
187 | return sh7750_general_events[event]; | ||
188 | } | ||
189 | |||
190 | static u64 sh7750_pmu_read(int idx) | ||
191 | { | ||
192 | return (u64)((u64)(__raw_readl(PMCTRH(idx)) & 0xffff) << 32) | | ||
193 | __raw_readl(PMCTRL(idx)); | ||
194 | } | ||
195 | |||
196 | static void sh7750_pmu_disable(struct hw_perf_event *hwc, int idx) | ||
197 | { | ||
198 | unsigned int tmp; | ||
199 | |||
200 | tmp = __raw_readw(PMCR(idx)); | ||
201 | tmp &= ~(PMCR_PMM_MASK | PMCR_PMEN); | ||
202 | __raw_writew(tmp, PMCR(idx)); | ||
203 | } | ||
204 | |||
205 | static void sh7750_pmu_enable(struct hw_perf_event *hwc, int idx) | ||
206 | { | ||
207 | __raw_writew(__raw_readw(PMCR(idx)) | PMCR_PMCLR, PMCR(idx)); | ||
208 | __raw_writew(hwc->config | PMCR_PMEN | PMCR_PMST, PMCR(idx)); | ||
209 | } | ||
210 | |||
211 | static void sh7750_pmu_disable_all(void) | ||
212 | { | ||
213 | int i; | ||
214 | |||
215 | for (i = 0; i < sh7750_pmu.num_events; i++) | ||
216 | __raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i)); | ||
217 | } | ||
218 | |||
219 | static void sh7750_pmu_enable_all(void) | ||
220 | { | ||
221 | int i; | ||
222 | |||
223 | for (i = 0; i < sh7750_pmu.num_events; i++) | ||
224 | __raw_writew(__raw_readw(PMCR(i)) | PMCR_PMEN, PMCR(i)); | ||
225 | } | ||
226 | |||
227 | static struct sh_pmu sh7750_pmu = { | ||
228 | .name = "SH7750", | ||
229 | .num_events = 2, | ||
230 | .event_map = sh7750_event_map, | ||
231 | .max_events = ARRAY_SIZE(sh7750_general_events), | ||
232 | .raw_event_mask = PMCR_PMM_MASK, | ||
233 | .cache_events = &sh7750_cache_events, | ||
234 | .read = sh7750_pmu_read, | ||
235 | .disable = sh7750_pmu_disable, | ||
236 | .enable = sh7750_pmu_enable, | ||
237 | .disable_all = sh7750_pmu_disable_all, | ||
238 | .enable_all = sh7750_pmu_enable_all, | ||
239 | }; | ||
240 | |||
241 | static int __init sh7750_pmu_init(void) | ||
242 | { | ||
243 | /* | ||
244 | * Make sure this CPU actually has perf counters. | ||
245 | */ | ||
246 | if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) { | ||
247 | pr_notice("HW perf events unsupported, software events only.\n"); | ||
248 | return -ENODEV; | ||
249 | } | ||
250 | |||
251 | return register_sh_pmu(&sh7750_pmu); | ||
252 | } | ||
253 | arch_initcall(sh7750_pmu_init); | ||
diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile index 490d5dc9e372..33bab477d2e2 100644 --- a/arch/sh/kernel/cpu/sh4a/Makefile +++ b/arch/sh/kernel/cpu/sh4a/Makefile | |||
@@ -44,3 +44,4 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7786) := pinmux-sh7786.o | |||
44 | obj-y += $(clock-y) | 44 | obj-y += $(clock-y) |
45 | obj-$(CONFIG_SMP) += $(smp-y) | 45 | obj-$(CONFIG_SMP) += $(smp-y) |
46 | obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y) | 46 | obj-$(CONFIG_GENERIC_GPIO) += $(pinmux-y) |
47 | obj-$(CONFIG_PERF_EVENTS) += perf_event.o | ||
diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c index dfe9192be63e..9db743802f06 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c | |||
@@ -152,7 +152,7 @@ struct clk div6_clks[] = { | |||
152 | SH_CLK_DIV6("fsia_clk", &div3_clk, FCLKACR, 0), | 152 | SH_CLK_DIV6("fsia_clk", &div3_clk, FCLKACR, 0), |
153 | SH_CLK_DIV6("fsib_clk", &div3_clk, FCLKBCR, 0), | 153 | SH_CLK_DIV6("fsib_clk", &div3_clk, FCLKBCR, 0), |
154 | SH_CLK_DIV6("irda_clk", &div3_clk, IRDACLKCR, 0), | 154 | SH_CLK_DIV6("irda_clk", &div3_clk, IRDACLKCR, 0), |
155 | SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, 0), | 155 | SH_CLK_DIV6("spu_clk", &div3_clk, SPUCLKCR, CLK_ENABLE_ON_INIT), |
156 | }; | 156 | }; |
157 | 157 | ||
158 | #define R_CLK (&r_clk) | 158 | #define R_CLK (&r_clk) |
diff --git a/arch/sh/kernel/cpu/sh4a/perf_event.c b/arch/sh/kernel/cpu/sh4a/perf_event.c new file mode 100644 index 000000000000..eddc21973fa1 --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/perf_event.c | |||
@@ -0,0 +1,269 @@ | |||
1 | /* | ||
2 | * Performance events support for SH-4A performance counters | ||
3 | * | ||
4 | * Copyright (C) 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <linux/irq.h> | ||
14 | #include <linux/perf_event.h> | ||
15 | #include <asm/processor.h> | ||
16 | |||
17 | #define PPC_CCBR(idx) (0xff200800 + (sizeof(u32) * idx)) | ||
18 | #define PPC_PMCTR(idx) (0xfc100000 + (sizeof(u32) * idx)) | ||
19 | |||
20 | #define CCBR_CIT_MASK (0x7ff << 6) | ||
21 | #define CCBR_DUC (1 << 3) | ||
22 | #define CCBR_CMDS (1 << 1) | ||
23 | #define CCBR_PPCE (1 << 0) | ||
24 | |||
25 | #define PPC_PMCAT 0xfc100080 | ||
26 | |||
27 | #define PMCAT_OVF3 (1 << 27) | ||
28 | #define PMCAT_CNN3 (1 << 26) | ||
29 | #define PMCAT_CLR3 (1 << 25) | ||
30 | #define PMCAT_OVF2 (1 << 19) | ||
31 | #define PMCAT_CLR2 (1 << 17) | ||
32 | #define PMCAT_OVF1 (1 << 11) | ||
33 | #define PMCAT_CNN1 (1 << 10) | ||
34 | #define PMCAT_CLR1 (1 << 9) | ||
35 | #define PMCAT_OVF0 (1 << 3) | ||
36 | #define PMCAT_CLR0 (1 << 1) | ||
37 | |||
38 | static struct sh_pmu sh4a_pmu; | ||
39 | |||
40 | /* | ||
41 | * Supported raw event codes: | ||
42 | * | ||
43 | * Event Code Description | ||
44 | * ---------- ----------- | ||
45 | * | ||
46 | * 0x0000 number of elapsed cycles | ||
47 | * 0x0200 number of elapsed cycles in privileged mode | ||
48 | * 0x0280 number of elapsed cycles while SR.BL is asserted | ||
49 | * 0x0202 instruction execution | ||
50 | * 0x0203 instruction execution in parallel | ||
51 | * 0x0204 number of unconditional branches | ||
52 | * 0x0208 number of exceptions | ||
53 | * 0x0209 number of interrupts | ||
54 | * 0x0220 UTLB miss caused by instruction fetch | ||
55 | * 0x0222 UTLB miss caused by operand access | ||
56 | * 0x02a0 number of ITLB misses | ||
57 | * 0x0028 number of accesses to instruction memories | ||
58 | * 0x0029 number of accesses to instruction cache | ||
59 | * 0x002a instruction cache miss | ||
60 | * 0x022e number of access to instruction X/Y memory | ||
61 | * 0x0030 number of reads to operand memories | ||
62 | * 0x0038 number of writes to operand memories | ||
63 | * 0x0031 number of operand cache read accesses | ||
64 | * 0x0039 number of operand cache write accesses | ||
65 | * 0x0032 operand cache read miss | ||
66 | * 0x003a operand cache write miss | ||
67 | * 0x0236 number of reads to operand X/Y memory | ||
68 | * 0x023e number of writes to operand X/Y memory | ||
69 | * 0x0237 number of reads to operand U memory | ||
70 | * 0x023f number of writes to operand U memory | ||
71 | * 0x0337 number of U memory read buffer misses | ||
72 | * 0x02b4 number of wait cycles due to operand read access | ||
73 | * 0x02bc number of wait cycles due to operand write access | ||
74 | * 0x0033 number of wait cycles due to operand cache read miss | ||
75 | * 0x003b number of wait cycles due to operand cache write miss | ||
76 | */ | ||
77 | |||
78 | /* | ||
79 | * Special reserved bits used by hardware emulators, read values will | ||
80 | * vary, but writes must always be 0. | ||
81 | */ | ||
82 | #define PMCAT_EMU_CLR_MASK ((1 << 24) | (1 << 16) | (1 << 8) | (1 << 0)) | ||
83 | |||
84 | static const int sh4a_general_events[] = { | ||
85 | [PERF_COUNT_HW_CPU_CYCLES] = 0x0000, | ||
86 | [PERF_COUNT_HW_INSTRUCTIONS] = 0x0202, | ||
87 | [PERF_COUNT_HW_CACHE_REFERENCES] = 0x0029, /* I-cache */ | ||
88 | [PERF_COUNT_HW_CACHE_MISSES] = 0x002a, /* I-cache */ | ||
89 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x0204, | ||
90 | [PERF_COUNT_HW_BRANCH_MISSES] = -1, | ||
91 | [PERF_COUNT_HW_BUS_CYCLES] = -1, | ||
92 | }; | ||
93 | |||
94 | #define C(x) PERF_COUNT_HW_CACHE_##x | ||
95 | |||
96 | static const int sh4a_cache_events | ||
97 | [PERF_COUNT_HW_CACHE_MAX] | ||
98 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
99 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = | ||
100 | { | ||
101 | [ C(L1D) ] = { | ||
102 | [ C(OP_READ) ] = { | ||
103 | [ C(RESULT_ACCESS) ] = 0x0031, | ||
104 | [ C(RESULT_MISS) ] = 0x0032, | ||
105 | }, | ||
106 | [ C(OP_WRITE) ] = { | ||
107 | [ C(RESULT_ACCESS) ] = 0x0039, | ||
108 | [ C(RESULT_MISS) ] = 0x003a, | ||
109 | }, | ||
110 | [ C(OP_PREFETCH) ] = { | ||
111 | [ C(RESULT_ACCESS) ] = 0, | ||
112 | [ C(RESULT_MISS) ] = 0, | ||
113 | }, | ||
114 | }, | ||
115 | |||
116 | [ C(L1I) ] = { | ||
117 | [ C(OP_READ) ] = { | ||
118 | [ C(RESULT_ACCESS) ] = 0x0029, | ||
119 | [ C(RESULT_MISS) ] = 0x002a, | ||
120 | }, | ||
121 | [ C(OP_WRITE) ] = { | ||
122 | [ C(RESULT_ACCESS) ] = -1, | ||
123 | [ C(RESULT_MISS) ] = -1, | ||
124 | }, | ||
125 | [ C(OP_PREFETCH) ] = { | ||
126 | [ C(RESULT_ACCESS) ] = 0, | ||
127 | [ C(RESULT_MISS) ] = 0, | ||
128 | }, | ||
129 | }, | ||
130 | |||
131 | [ C(LL) ] = { | ||
132 | [ C(OP_READ) ] = { | ||
133 | [ C(RESULT_ACCESS) ] = 0x0030, | ||
134 | [ C(RESULT_MISS) ] = 0, | ||
135 | }, | ||
136 | [ C(OP_WRITE) ] = { | ||
137 | [ C(RESULT_ACCESS) ] = 0x0038, | ||
138 | [ C(RESULT_MISS) ] = 0, | ||
139 | }, | ||
140 | [ C(OP_PREFETCH) ] = { | ||
141 | [ C(RESULT_ACCESS) ] = 0, | ||
142 | [ C(RESULT_MISS) ] = 0, | ||
143 | }, | ||
144 | }, | ||
145 | |||
146 | [ C(DTLB) ] = { | ||
147 | [ C(OP_READ) ] = { | ||
148 | [ C(RESULT_ACCESS) ] = 0x0222, | ||
149 | [ C(RESULT_MISS) ] = 0x0220, | ||
150 | }, | ||
151 | [ C(OP_WRITE) ] = { | ||
152 | [ C(RESULT_ACCESS) ] = 0, | ||
153 | [ C(RESULT_MISS) ] = 0, | ||
154 | }, | ||
155 | [ C(OP_PREFETCH) ] = { | ||
156 | [ C(RESULT_ACCESS) ] = 0, | ||
157 | [ C(RESULT_MISS) ] = 0, | ||
158 | }, | ||
159 | }, | ||
160 | |||
161 | [ C(ITLB) ] = { | ||
162 | [ C(OP_READ) ] = { | ||
163 | [ C(RESULT_ACCESS) ] = 0, | ||
164 | [ C(RESULT_MISS) ] = 0x02a0, | ||
165 | }, | ||
166 | [ C(OP_WRITE) ] = { | ||
167 | [ C(RESULT_ACCESS) ] = -1, | ||
168 | [ C(RESULT_MISS) ] = -1, | ||
169 | }, | ||
170 | [ C(OP_PREFETCH) ] = { | ||
171 | [ C(RESULT_ACCESS) ] = -1, | ||
172 | [ C(RESULT_MISS) ] = -1, | ||
173 | }, | ||
174 | }, | ||
175 | |||
176 | [ C(BPU) ] = { | ||
177 | [ C(OP_READ) ] = { | ||
178 | [ C(RESULT_ACCESS) ] = -1, | ||
179 | [ C(RESULT_MISS) ] = -1, | ||
180 | }, | ||
181 | [ C(OP_WRITE) ] = { | ||
182 | [ C(RESULT_ACCESS) ] = -1, | ||
183 | [ C(RESULT_MISS) ] = -1, | ||
184 | }, | ||
185 | [ C(OP_PREFETCH) ] = { | ||
186 | [ C(RESULT_ACCESS) ] = -1, | ||
187 | [ C(RESULT_MISS) ] = -1, | ||
188 | }, | ||
189 | }, | ||
190 | }; | ||
191 | |||
192 | static int sh4a_event_map(int event) | ||
193 | { | ||
194 | return sh4a_general_events[event]; | ||
195 | } | ||
196 | |||
197 | static u64 sh4a_pmu_read(int idx) | ||
198 | { | ||
199 | return __raw_readl(PPC_PMCTR(idx)); | ||
200 | } | ||
201 | |||
202 | static void sh4a_pmu_disable(struct hw_perf_event *hwc, int idx) | ||
203 | { | ||
204 | unsigned int tmp; | ||
205 | |||
206 | tmp = __raw_readl(PPC_CCBR(idx)); | ||
207 | tmp &= ~(CCBR_CIT_MASK | CCBR_DUC); | ||
208 | __raw_writel(tmp, PPC_CCBR(idx)); | ||
209 | } | ||
210 | |||
211 | static void sh4a_pmu_enable(struct hw_perf_event *hwc, int idx) | ||
212 | { | ||
213 | unsigned int tmp; | ||
214 | |||
215 | tmp = __raw_readl(PPC_PMCAT); | ||
216 | tmp &= ~PMCAT_EMU_CLR_MASK; | ||
217 | tmp |= idx ? PMCAT_CLR1 : PMCAT_CLR0; | ||
218 | __raw_writel(tmp, PPC_PMCAT); | ||
219 | |||
220 | tmp = __raw_readl(PPC_CCBR(idx)); | ||
221 | tmp |= (hwc->config << 6) | CCBR_CMDS | CCBR_PPCE; | ||
222 | __raw_writel(tmp, PPC_CCBR(idx)); | ||
223 | |||
224 | __raw_writel(__raw_readl(PPC_CCBR(idx)) | CCBR_DUC, PPC_CCBR(idx)); | ||
225 | } | ||
226 | |||
227 | static void sh4a_pmu_disable_all(void) | ||
228 | { | ||
229 | int i; | ||
230 | |||
231 | for (i = 0; i < sh4a_pmu.num_events; i++) | ||
232 | __raw_writel(__raw_readl(PPC_CCBR(i)) & ~CCBR_DUC, PPC_CCBR(i)); | ||
233 | } | ||
234 | |||
235 | static void sh4a_pmu_enable_all(void) | ||
236 | { | ||
237 | int i; | ||
238 | |||
239 | for (i = 0; i < sh4a_pmu.num_events; i++) | ||
240 | __raw_writel(__raw_readl(PPC_CCBR(i)) | CCBR_DUC, PPC_CCBR(i)); | ||
241 | } | ||
242 | |||
243 | static struct sh_pmu sh4a_pmu = { | ||
244 | .name = "SH-4A", | ||
245 | .num_events = 2, | ||
246 | .event_map = sh4a_event_map, | ||
247 | .max_events = ARRAY_SIZE(sh4a_general_events), | ||
248 | .raw_event_mask = 0x3ff, | ||
249 | .cache_events = &sh4a_cache_events, | ||
250 | .read = sh4a_pmu_read, | ||
251 | .disable = sh4a_pmu_disable, | ||
252 | .enable = sh4a_pmu_enable, | ||
253 | .disable_all = sh4a_pmu_disable_all, | ||
254 | .enable_all = sh4a_pmu_enable_all, | ||
255 | }; | ||
256 | |||
257 | static int __init sh4a_pmu_init(void) | ||
258 | { | ||
259 | /* | ||
260 | * Make sure this CPU actually has perf counters. | ||
261 | */ | ||
262 | if (!(boot_cpu_data.flags & CPU_HAS_PERF_COUNTER)) { | ||
263 | pr_notice("HW perf events unsupported, software events only.\n"); | ||
264 | return -ENODEV; | ||
265 | } | ||
266 | |||
267 | return register_sh_pmu(&sh4a_pmu); | ||
268 | } | ||
269 | arch_initcall(sh4a_pmu_init); | ||
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c index f3851fd757ec..845e89c936e7 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7724.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/uio_driver.h> | 20 | #include <linux/uio_driver.h> |
21 | #include <linux/sh_timer.h> | 21 | #include <linux/sh_timer.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/notifier.h> | ||
24 | #include <asm/suspend.h> | ||
23 | #include <asm/clock.h> | 25 | #include <asm/clock.h> |
24 | #include <asm/mmzone.h> | 26 | #include <asm/mmzone.h> |
25 | #include <cpu/sh7724.h> | 27 | #include <cpu/sh7724.h> |
@@ -202,7 +204,7 @@ static struct resource veu0_resources[] = { | |||
202 | [0] = { | 204 | [0] = { |
203 | .name = "VEU3F0", | 205 | .name = "VEU3F0", |
204 | .start = 0xfe920000, | 206 | .start = 0xfe920000, |
205 | .end = 0xfe9200cb - 1, | 207 | .end = 0xfe9200cb, |
206 | .flags = IORESOURCE_MEM, | 208 | .flags = IORESOURCE_MEM, |
207 | }, | 209 | }, |
208 | [1] = { | 210 | [1] = { |
@@ -234,7 +236,7 @@ static struct resource veu1_resources[] = { | |||
234 | [0] = { | 236 | [0] = { |
235 | .name = "VEU3F1", | 237 | .name = "VEU3F1", |
236 | .start = 0xfe924000, | 238 | .start = 0xfe924000, |
237 | .end = 0xfe9240cb - 1, | 239 | .end = 0xfe9240cb, |
238 | .flags = IORESOURCE_MEM, | 240 | .flags = IORESOURCE_MEM, |
239 | }, | 241 | }, |
240 | [1] = { | 242 | [1] = { |
@@ -523,6 +525,70 @@ static struct platform_device jpu_device = { | |||
523 | }, | 525 | }, |
524 | }; | 526 | }; |
525 | 527 | ||
528 | /* SPU2DSP0 */ | ||
529 | static struct uio_info spu0_platform_data = { | ||
530 | .name = "SPU2DSP0", | ||
531 | .version = "0", | ||
532 | .irq = 86, | ||
533 | }; | ||
534 | |||
535 | static struct resource spu0_resources[] = { | ||
536 | [0] = { | ||
537 | .name = "SPU2DSP0", | ||
538 | .start = 0xFE200000, | ||
539 | .end = 0xFE2FFFFF, | ||
540 | .flags = IORESOURCE_MEM, | ||
541 | }, | ||
542 | [1] = { | ||
543 | /* place holder for contiguous memory */ | ||
544 | }, | ||
545 | }; | ||
546 | |||
547 | static struct platform_device spu0_device = { | ||
548 | .name = "uio_pdrv_genirq", | ||
549 | .id = 4, | ||
550 | .dev = { | ||
551 | .platform_data = &spu0_platform_data, | ||
552 | }, | ||
553 | .resource = spu0_resources, | ||
554 | .num_resources = ARRAY_SIZE(spu0_resources), | ||
555 | .archdata = { | ||
556 | .hwblk_id = HWBLK_SPU, | ||
557 | }, | ||
558 | }; | ||
559 | |||
560 | /* SPU2DSP1 */ | ||
561 | static struct uio_info spu1_platform_data = { | ||
562 | .name = "SPU2DSP1", | ||
563 | .version = "0", | ||
564 | .irq = 87, | ||
565 | }; | ||
566 | |||
567 | static struct resource spu1_resources[] = { | ||
568 | [0] = { | ||
569 | .name = "SPU2DSP1", | ||
570 | .start = 0xFE300000, | ||
571 | .end = 0xFE3FFFFF, | ||
572 | .flags = IORESOURCE_MEM, | ||
573 | }, | ||
574 | [1] = { | ||
575 | /* place holder for contiguous memory */ | ||
576 | }, | ||
577 | }; | ||
578 | |||
579 | static struct platform_device spu1_device = { | ||
580 | .name = "uio_pdrv_genirq", | ||
581 | .id = 5, | ||
582 | .dev = { | ||
583 | .platform_data = &spu1_platform_data, | ||
584 | }, | ||
585 | .resource = spu1_resources, | ||
586 | .num_resources = ARRAY_SIZE(spu1_resources), | ||
587 | .archdata = { | ||
588 | .hwblk_id = HWBLK_SPU, | ||
589 | }, | ||
590 | }; | ||
591 | |||
526 | static struct platform_device *sh7724_devices[] __initdata = { | 592 | static struct platform_device *sh7724_devices[] __initdata = { |
527 | &cmt_device, | 593 | &cmt_device, |
528 | &tmu0_device, | 594 | &tmu0_device, |
@@ -539,6 +605,8 @@ static struct platform_device *sh7724_devices[] __initdata = { | |||
539 | &veu0_device, | 605 | &veu0_device, |
540 | &veu1_device, | 606 | &veu1_device, |
541 | &jpu_device, | 607 | &jpu_device, |
608 | &spu0_device, | ||
609 | &spu1_device, | ||
542 | }; | 610 | }; |
543 | 611 | ||
544 | static int __init sh7724_devices_setup(void) | 612 | static int __init sh7724_devices_setup(void) |
@@ -547,6 +615,8 @@ static int __init sh7724_devices_setup(void) | |||
547 | platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20); | 615 | platform_resource_setup_memory(&veu0_device, "veu0", 2 << 20); |
548 | platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20); | 616 | platform_resource_setup_memory(&veu1_device, "veu1", 2 << 20); |
549 | platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20); | 617 | platform_resource_setup_memory(&jpu_device, "jpu", 2 << 20); |
618 | platform_resource_setup_memory(&spu0_device, "spu0", 2 << 20); | ||
619 | platform_resource_setup_memory(&spu1_device, "spu1", 2 << 20); | ||
550 | 620 | ||
551 | return platform_add_devices(sh7724_devices, | 621 | return platform_add_devices(sh7724_devices, |
552 | ARRAY_SIZE(sh7724_devices)); | 622 | ARRAY_SIZE(sh7724_devices)); |
@@ -827,3 +897,193 @@ void __init plat_irq_setup(void) | |||
827 | { | 897 | { |
828 | register_intc_controller(&intc_desc); | 898 | register_intc_controller(&intc_desc); |
829 | } | 899 | } |
900 | |||
901 | static struct { | ||
902 | /* BSC */ | ||
903 | unsigned long mmselr; | ||
904 | unsigned long cs0bcr; | ||
905 | unsigned long cs4bcr; | ||
906 | unsigned long cs5abcr; | ||
907 | unsigned long cs5bbcr; | ||
908 | unsigned long cs6abcr; | ||
909 | unsigned long cs6bbcr; | ||
910 | unsigned long cs4wcr; | ||
911 | unsigned long cs5awcr; | ||
912 | unsigned long cs5bwcr; | ||
913 | unsigned long cs6awcr; | ||
914 | unsigned long cs6bwcr; | ||
915 | /* INTC */ | ||
916 | unsigned short ipra; | ||
917 | unsigned short iprb; | ||
918 | unsigned short iprc; | ||
919 | unsigned short iprd; | ||
920 | unsigned short ipre; | ||
921 | unsigned short iprf; | ||
922 | unsigned short iprg; | ||
923 | unsigned short iprh; | ||
924 | unsigned short ipri; | ||
925 | unsigned short iprj; | ||
926 | unsigned short iprk; | ||
927 | unsigned short iprl; | ||
928 | unsigned char imr0; | ||
929 | unsigned char imr1; | ||
930 | unsigned char imr2; | ||
931 | unsigned char imr3; | ||
932 | unsigned char imr4; | ||
933 | unsigned char imr5; | ||
934 | unsigned char imr6; | ||
935 | unsigned char imr7; | ||
936 | unsigned char imr8; | ||
937 | unsigned char imr9; | ||
938 | unsigned char imr10; | ||
939 | unsigned char imr11; | ||
940 | unsigned char imr12; | ||
941 | /* RWDT */ | ||
942 | unsigned short rwtcnt; | ||
943 | unsigned short rwtcsr; | ||
944 | /* CPG */ | ||
945 | unsigned long irdaclk; | ||
946 | unsigned long spuclk; | ||
947 | } sh7724_rstandby_state; | ||
948 | |||
949 | static int sh7724_pre_sleep_notifier_call(struct notifier_block *nb, | ||
950 | unsigned long flags, void *unused) | ||
951 | { | ||
952 | if (!(flags & SUSP_SH_RSTANDBY)) | ||
953 | return NOTIFY_DONE; | ||
954 | |||
955 | /* BCR */ | ||
956 | sh7724_rstandby_state.mmselr = __raw_readl(0xff800020); /* MMSELR */ | ||
957 | sh7724_rstandby_state.mmselr |= 0xa5a50000; | ||
958 | sh7724_rstandby_state.cs0bcr = __raw_readl(0xfec10004); /* CS0BCR */ | ||
959 | sh7724_rstandby_state.cs4bcr = __raw_readl(0xfec10010); /* CS4BCR */ | ||
960 | sh7724_rstandby_state.cs5abcr = __raw_readl(0xfec10014); /* CS5ABCR */ | ||
961 | sh7724_rstandby_state.cs5bbcr = __raw_readl(0xfec10018); /* CS5BBCR */ | ||
962 | sh7724_rstandby_state.cs6abcr = __raw_readl(0xfec1001c); /* CS6ABCR */ | ||
963 | sh7724_rstandby_state.cs6bbcr = __raw_readl(0xfec10020); /* CS6BBCR */ | ||
964 | sh7724_rstandby_state.cs4wcr = __raw_readl(0xfec10030); /* CS4WCR */ | ||
965 | sh7724_rstandby_state.cs5awcr = __raw_readl(0xfec10034); /* CS5AWCR */ | ||
966 | sh7724_rstandby_state.cs5bwcr = __raw_readl(0xfec10038); /* CS5BWCR */ | ||
967 | sh7724_rstandby_state.cs6awcr = __raw_readl(0xfec1003c); /* CS6AWCR */ | ||
968 | sh7724_rstandby_state.cs6bwcr = __raw_readl(0xfec10040); /* CS6BWCR */ | ||
969 | |||
970 | /* INTC */ | ||
971 | sh7724_rstandby_state.ipra = __raw_readw(0xa4080000); /* IPRA */ | ||
972 | sh7724_rstandby_state.iprb = __raw_readw(0xa4080004); /* IPRB */ | ||
973 | sh7724_rstandby_state.iprc = __raw_readw(0xa4080008); /* IPRC */ | ||
974 | sh7724_rstandby_state.iprd = __raw_readw(0xa408000c); /* IPRD */ | ||
975 | sh7724_rstandby_state.ipre = __raw_readw(0xa4080010); /* IPRE */ | ||
976 | sh7724_rstandby_state.iprf = __raw_readw(0xa4080014); /* IPRF */ | ||
977 | sh7724_rstandby_state.iprg = __raw_readw(0xa4080018); /* IPRG */ | ||
978 | sh7724_rstandby_state.iprh = __raw_readw(0xa408001c); /* IPRH */ | ||
979 | sh7724_rstandby_state.ipri = __raw_readw(0xa4080020); /* IPRI */ | ||
980 | sh7724_rstandby_state.iprj = __raw_readw(0xa4080024); /* IPRJ */ | ||
981 | sh7724_rstandby_state.iprk = __raw_readw(0xa4080028); /* IPRK */ | ||
982 | sh7724_rstandby_state.iprl = __raw_readw(0xa408002c); /* IPRL */ | ||
983 | sh7724_rstandby_state.imr0 = __raw_readb(0xa4080080); /* IMR0 */ | ||
984 | sh7724_rstandby_state.imr1 = __raw_readb(0xa4080084); /* IMR1 */ | ||
985 | sh7724_rstandby_state.imr2 = __raw_readb(0xa4080088); /* IMR2 */ | ||
986 | sh7724_rstandby_state.imr3 = __raw_readb(0xa408008c); /* IMR3 */ | ||
987 | sh7724_rstandby_state.imr4 = __raw_readb(0xa4080090); /* IMR4 */ | ||
988 | sh7724_rstandby_state.imr5 = __raw_readb(0xa4080094); /* IMR5 */ | ||
989 | sh7724_rstandby_state.imr6 = __raw_readb(0xa4080098); /* IMR6 */ | ||
990 | sh7724_rstandby_state.imr7 = __raw_readb(0xa408009c); /* IMR7 */ | ||
991 | sh7724_rstandby_state.imr8 = __raw_readb(0xa40800a0); /* IMR8 */ | ||
992 | sh7724_rstandby_state.imr9 = __raw_readb(0xa40800a4); /* IMR9 */ | ||
993 | sh7724_rstandby_state.imr10 = __raw_readb(0xa40800a8); /* IMR10 */ | ||
994 | sh7724_rstandby_state.imr11 = __raw_readb(0xa40800ac); /* IMR11 */ | ||
995 | sh7724_rstandby_state.imr12 = __raw_readb(0xa40800b0); /* IMR12 */ | ||
996 | |||
997 | /* RWDT */ | ||
998 | sh7724_rstandby_state.rwtcnt = __raw_readb(0xa4520000); /* RWTCNT */ | ||
999 | sh7724_rstandby_state.rwtcnt |= 0x5a00; | ||
1000 | sh7724_rstandby_state.rwtcsr = __raw_readb(0xa4520004); /* RWTCSR */ | ||
1001 | sh7724_rstandby_state.rwtcsr |= 0xa500; | ||
1002 | __raw_writew(sh7724_rstandby_state.rwtcsr & 0x07, 0xa4520004); | ||
1003 | |||
1004 | /* CPG */ | ||
1005 | sh7724_rstandby_state.irdaclk = __raw_readl(0xa4150018); /* IRDACLKCR */ | ||
1006 | sh7724_rstandby_state.spuclk = __raw_readl(0xa415003c); /* SPUCLKCR */ | ||
1007 | |||
1008 | return NOTIFY_DONE; | ||
1009 | } | ||
1010 | |||
1011 | static int sh7724_post_sleep_notifier_call(struct notifier_block *nb, | ||
1012 | unsigned long flags, void *unused) | ||
1013 | { | ||
1014 | if (!(flags & SUSP_SH_RSTANDBY)) | ||
1015 | return NOTIFY_DONE; | ||
1016 | |||
1017 | /* BCR */ | ||
1018 | __raw_writel(sh7724_rstandby_state.mmselr, 0xff800020); /* MMSELR */ | ||
1019 | __raw_writel(sh7724_rstandby_state.cs0bcr, 0xfec10004); /* CS0BCR */ | ||
1020 | __raw_writel(sh7724_rstandby_state.cs4bcr, 0xfec10010); /* CS4BCR */ | ||
1021 | __raw_writel(sh7724_rstandby_state.cs5abcr, 0xfec10014); /* CS5ABCR */ | ||
1022 | __raw_writel(sh7724_rstandby_state.cs5bbcr, 0xfec10018); /* CS5BBCR */ | ||
1023 | __raw_writel(sh7724_rstandby_state.cs6abcr, 0xfec1001c); /* CS6ABCR */ | ||
1024 | __raw_writel(sh7724_rstandby_state.cs6bbcr, 0xfec10020); /* CS6BBCR */ | ||
1025 | __raw_writel(sh7724_rstandby_state.cs4wcr, 0xfec10030); /* CS4WCR */ | ||
1026 | __raw_writel(sh7724_rstandby_state.cs5awcr, 0xfec10034); /* CS5AWCR */ | ||
1027 | __raw_writel(sh7724_rstandby_state.cs5bwcr, 0xfec10038); /* CS5BWCR */ | ||
1028 | __raw_writel(sh7724_rstandby_state.cs6awcr, 0xfec1003c); /* CS6AWCR */ | ||
1029 | __raw_writel(sh7724_rstandby_state.cs6bwcr, 0xfec10040); /* CS6BWCR */ | ||
1030 | |||
1031 | /* INTC */ | ||
1032 | __raw_writew(sh7724_rstandby_state.ipra, 0xa4080000); /* IPRA */ | ||
1033 | __raw_writew(sh7724_rstandby_state.iprb, 0xa4080004); /* IPRB */ | ||
1034 | __raw_writew(sh7724_rstandby_state.iprc, 0xa4080008); /* IPRC */ | ||
1035 | __raw_writew(sh7724_rstandby_state.iprd, 0xa408000c); /* IPRD */ | ||
1036 | __raw_writew(sh7724_rstandby_state.ipre, 0xa4080010); /* IPRE */ | ||
1037 | __raw_writew(sh7724_rstandby_state.iprf, 0xa4080014); /* IPRF */ | ||
1038 | __raw_writew(sh7724_rstandby_state.iprg, 0xa4080018); /* IPRG */ | ||
1039 | __raw_writew(sh7724_rstandby_state.iprh, 0xa408001c); /* IPRH */ | ||
1040 | __raw_writew(sh7724_rstandby_state.ipri, 0xa4080020); /* IPRI */ | ||
1041 | __raw_writew(sh7724_rstandby_state.iprj, 0xa4080024); /* IPRJ */ | ||
1042 | __raw_writew(sh7724_rstandby_state.iprk, 0xa4080028); /* IPRK */ | ||
1043 | __raw_writew(sh7724_rstandby_state.iprl, 0xa408002c); /* IPRL */ | ||
1044 | __raw_writeb(sh7724_rstandby_state.imr0, 0xa4080080); /* IMR0 */ | ||
1045 | __raw_writeb(sh7724_rstandby_state.imr1, 0xa4080084); /* IMR1 */ | ||
1046 | __raw_writeb(sh7724_rstandby_state.imr2, 0xa4080088); /* IMR2 */ | ||
1047 | __raw_writeb(sh7724_rstandby_state.imr3, 0xa408008c); /* IMR3 */ | ||
1048 | __raw_writeb(sh7724_rstandby_state.imr4, 0xa4080090); /* IMR4 */ | ||
1049 | __raw_writeb(sh7724_rstandby_state.imr5, 0xa4080094); /* IMR5 */ | ||
1050 | __raw_writeb(sh7724_rstandby_state.imr6, 0xa4080098); /* IMR6 */ | ||
1051 | __raw_writeb(sh7724_rstandby_state.imr7, 0xa408009c); /* IMR7 */ | ||
1052 | __raw_writeb(sh7724_rstandby_state.imr8, 0xa40800a0); /* IMR8 */ | ||
1053 | __raw_writeb(sh7724_rstandby_state.imr9, 0xa40800a4); /* IMR9 */ | ||
1054 | __raw_writeb(sh7724_rstandby_state.imr10, 0xa40800a8); /* IMR10 */ | ||
1055 | __raw_writeb(sh7724_rstandby_state.imr11, 0xa40800ac); /* IMR11 */ | ||
1056 | __raw_writeb(sh7724_rstandby_state.imr12, 0xa40800b0); /* IMR12 */ | ||
1057 | |||
1058 | /* RWDT */ | ||
1059 | __raw_writew(sh7724_rstandby_state.rwtcnt, 0xa4520000); /* RWTCNT */ | ||
1060 | __raw_writew(sh7724_rstandby_state.rwtcsr, 0xa4520004); /* RWTCSR */ | ||
1061 | |||
1062 | /* CPG */ | ||
1063 | __raw_writel(sh7724_rstandby_state.irdaclk, 0xa4150018); /* IRDACLKCR */ | ||
1064 | __raw_writel(sh7724_rstandby_state.spuclk, 0xa415003c); /* SPUCLKCR */ | ||
1065 | |||
1066 | return NOTIFY_DONE; | ||
1067 | } | ||
1068 | |||
1069 | static struct notifier_block sh7724_pre_sleep_notifier = { | ||
1070 | .notifier_call = sh7724_pre_sleep_notifier_call, | ||
1071 | .priority = SH_MOBILE_PRE(SH_MOBILE_SLEEP_CPU), | ||
1072 | }; | ||
1073 | |||
1074 | static struct notifier_block sh7724_post_sleep_notifier = { | ||
1075 | .notifier_call = sh7724_post_sleep_notifier_call, | ||
1076 | .priority = SH_MOBILE_POST(SH_MOBILE_SLEEP_CPU), | ||
1077 | }; | ||
1078 | |||
1079 | static int __init sh7724_sleep_setup(void) | ||
1080 | { | ||
1081 | atomic_notifier_chain_register(&sh_mobile_pre_sleep_notifier_list, | ||
1082 | &sh7724_pre_sleep_notifier); | ||
1083 | |||
1084 | atomic_notifier_chain_register(&sh_mobile_post_sleep_notifier_list, | ||
1085 | &sh7724_post_sleep_notifier); | ||
1086 | return 0; | ||
1087 | } | ||
1088 | arch_initcall(sh7724_sleep_setup); | ||
1089 | |||
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c index e848443deeb9..c7ba9166e18a 100644 --- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c | |||
@@ -15,6 +15,15 @@ | |||
15 | #include <linux/sh_timer.h> | 15 | #include <linux/sh_timer.h> |
16 | #include <asm/mmzone.h> | 16 | #include <asm/mmzone.h> |
17 | 17 | ||
18 | /* | ||
19 | * This intentionally only registers SCIF ports 0, 1, and 3. SCIF 2 | ||
20 | * INTEVT values overlap with the FPU EXPEVT ones, requiring special | ||
21 | * demuxing in the exception dispatch path. | ||
22 | * | ||
23 | * As this overlap is something that never should have made it in to | ||
24 | * silicon in the first place, we just refuse to deal with the port at | ||
25 | * all rather than adding infrastructure to hack around it. | ||
26 | */ | ||
18 | static struct plat_sci_port sci_platform_data[] = { | 27 | static struct plat_sci_port sci_platform_data[] = { |
19 | { | 28 | { |
20 | .mapbase = 0xffc30000, | 29 | .mapbase = 0xffc30000, |
@@ -27,11 +36,6 @@ static struct plat_sci_port sci_platform_data[] = { | |||
27 | .type = PORT_SCIF, | 36 | .type = PORT_SCIF, |
28 | .irqs = { 44, 45, 47, 46 }, | 37 | .irqs = { 44, 45, 47, 46 }, |
29 | }, { | 38 | }, { |
30 | .mapbase = 0xffc50000, | ||
31 | .flags = UPF_BOOT_AUTOCONF, | ||
32 | .type = PORT_SCIF, | ||
33 | .irqs = { 48, 49, 51, 50 }, | ||
34 | }, { | ||
35 | .mapbase = 0xffc60000, | 39 | .mapbase = 0xffc60000, |
36 | .flags = UPF_BOOT_AUTOCONF, | 40 | .flags = UPF_BOOT_AUTOCONF, |
37 | .type = PORT_SCIF, | 41 | .type = PORT_SCIF, |
@@ -268,7 +272,11 @@ enum { | |||
268 | UNUSED = 0, | 272 | UNUSED = 0, |
269 | 273 | ||
270 | /* interrupt sources */ | 274 | /* interrupt sources */ |
271 | IRL, IRQ0, IRQ1, IRQ2, IRQ3, | 275 | IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH, |
276 | IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH, | ||
277 | IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH, | ||
278 | IRL_HHLL, IRL_HHLH, IRL_HHHL, | ||
279 | IRQ0, IRQ1, IRQ2, IRQ3, | ||
272 | HUDII, | 280 | HUDII, |
273 | TMU0, TMU1, TMU2, TMU3, TMU4, TMU5, | 281 | TMU0, TMU1, TMU2, TMU3, TMU4, TMU5, |
274 | PCII0, PCII1, PCII2, PCII3, PCII4, | 282 | PCII0, PCII1, PCII2, PCII3, PCII4, |
@@ -291,7 +299,7 @@ enum { | |||
291 | INTICI4, INTICI5, INTICI6, INTICI7, | 299 | INTICI4, INTICI5, INTICI6, INTICI7, |
292 | 300 | ||
293 | /* interrupt groups */ | 301 | /* interrupt groups */ |
294 | PCII56789, SCIF0, SCIF1, SCIF2, SCIF3, | 302 | IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3, |
295 | DMAC0, DMAC1, | 303 | DMAC0, DMAC1, |
296 | }; | 304 | }; |
297 | 305 | ||
@@ -309,8 +317,6 @@ static struct intc_vect vectors[] __initdata = { | |||
309 | INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760), | 317 | INTC_VECT(SCIF0_BRI, 0x740), INTC_VECT(SCIF0_TXI, 0x760), |
310 | INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0), | 318 | INTC_VECT(SCIF1_ERI, 0x780), INTC_VECT(SCIF1_RXI, 0x7a0), |
311 | INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0), | 319 | INTC_VECT(SCIF1_BRI, 0x7c0), INTC_VECT(SCIF1_TXI, 0x7e0), |
312 | INTC_VECT(SCIF2_ERI, 0x800), INTC_VECT(SCIF2_RXI, 0x820), | ||
313 | INTC_VECT(SCIF2_BRI, 0x840), INTC_VECT(SCIF2_TXI, 0x860), | ||
314 | INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0), | 320 | INTC_VECT(SCIF3_ERI, 0x880), INTC_VECT(SCIF3_RXI, 0x8a0), |
315 | INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0), | 321 | INTC_VECT(SCIF3_BRI, 0x8c0), INTC_VECT(SCIF3_TXI, 0x8e0), |
316 | INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920), | 322 | INTC_VECT(DMAC0_DMINT0, 0x900), INTC_VECT(DMAC0_DMINT1, 0x920), |
@@ -344,10 +350,13 @@ static struct intc_vect vectors[] __initdata = { | |||
344 | }; | 350 | }; |
345 | 351 | ||
346 | static struct intc_group groups[] __initdata = { | 352 | static struct intc_group groups[] __initdata = { |
353 | INTC_GROUP(IRL, IRL_LLLL, IRL_LLLH, IRL_LLHL, IRL_LLHH, | ||
354 | IRL_LHLL, IRL_LHLH, IRL_LHHL, IRL_LHHH, | ||
355 | IRL_HLLL, IRL_HLLH, IRL_HLHL, IRL_HLHH, | ||
356 | IRL_HHLL, IRL_HHLH, IRL_HHHL), | ||
347 | INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9), | 357 | INTC_GROUP(PCII56789, PCII5, PCII6, PCII7, PCII8, PCII9), |
348 | INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), | 358 | INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), |
349 | INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI), | 359 | INTC_GROUP(SCIF1, SCIF1_ERI, SCIF1_RXI, SCIF1_BRI, SCIF1_TXI), |
350 | INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI), | ||
351 | INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI), | 360 | INTC_GROUP(SCIF3, SCIF3_ERI, SCIF3_RXI, SCIF3_BRI, SCIF3_TXI), |
352 | INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, | 361 | INTC_GROUP(DMAC0, DMAC0_DMINT0, DMAC0_DMINT1, DMAC0_DMINT2, |
353 | DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE), | 362 | DMAC0_DMINT3, DMAC0_DMINT4, DMAC0_DMINT5, DMAC0_DMAE), |
@@ -419,14 +428,14 @@ static DECLARE_INTC_DESC(intc_desc_irq, "shx3-irq", vectors_irq, groups, | |||
419 | 428 | ||
420 | /* External interrupt pins in IRL mode */ | 429 | /* External interrupt pins in IRL mode */ |
421 | static struct intc_vect vectors_irl[] __initdata = { | 430 | static struct intc_vect vectors_irl[] __initdata = { |
422 | INTC_VECT(IRL, 0x200), INTC_VECT(IRL, 0x220), | 431 | INTC_VECT(IRL_LLLL, 0x200), INTC_VECT(IRL_LLLH, 0x220), |
423 | INTC_VECT(IRL, 0x240), INTC_VECT(IRL, 0x260), | 432 | INTC_VECT(IRL_LLHL, 0x240), INTC_VECT(IRL_LLHH, 0x260), |
424 | INTC_VECT(IRL, 0x280), INTC_VECT(IRL, 0x2a0), | 433 | INTC_VECT(IRL_LHLL, 0x280), INTC_VECT(IRL_LHLH, 0x2a0), |
425 | INTC_VECT(IRL, 0x2c0), INTC_VECT(IRL, 0x2e0), | 434 | INTC_VECT(IRL_LHHL, 0x2c0), INTC_VECT(IRL_LHHH, 0x2e0), |
426 | INTC_VECT(IRL, 0x300), INTC_VECT(IRL, 0x320), | 435 | INTC_VECT(IRL_HLLL, 0x300), INTC_VECT(IRL_HLLH, 0x320), |
427 | INTC_VECT(IRL, 0x340), INTC_VECT(IRL, 0x360), | 436 | INTC_VECT(IRL_HLHL, 0x340), INTC_VECT(IRL_HLHH, 0x360), |
428 | INTC_VECT(IRL, 0x380), INTC_VECT(IRL, 0x3a0), | 437 | INTC_VECT(IRL_HHLL, 0x380), INTC_VECT(IRL_HHLH, 0x3a0), |
429 | INTC_VECT(IRL, 0x3c0), | 438 | INTC_VECT(IRL_HHHL, 0x3c0), |
430 | }; | 439 | }; |
431 | 440 | ||
432 | static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups, | 441 | static DECLARE_INTC_DESC(intc_desc_irl, "shx3-irl", vectors_irl, groups, |
diff --git a/arch/sh/kernel/cpu/sh4a/smp-shx3.c b/arch/sh/kernel/cpu/sh4a/smp-shx3.c index 185ec3976a25..5863e0c4d02f 100644 --- a/arch/sh/kernel/cpu/sh4a/smp-shx3.c +++ b/arch/sh/kernel/cpu/sh4a/smp-shx3.c | |||
@@ -14,6 +14,13 @@ | |||
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
16 | 16 | ||
17 | #define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12)) | ||
18 | #define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12)) | ||
19 | |||
20 | #define STBCR_MSTP 0x00000001 | ||
21 | #define STBCR_RESET 0x00000002 | ||
22 | #define STBCR_LTSLP 0x80000000 | ||
23 | |||
17 | static irqreturn_t ipi_interrupt_handler(int irq, void *arg) | 24 | static irqreturn_t ipi_interrupt_handler(int irq, void *arg) |
18 | { | 25 | { |
19 | unsigned int message = (unsigned int)(long)arg; | 26 | unsigned int message = (unsigned int)(long)arg; |
@@ -21,9 +28,9 @@ static irqreturn_t ipi_interrupt_handler(int irq, void *arg) | |||
21 | unsigned int offs = 4 * cpu; | 28 | unsigned int offs = 4 * cpu; |
22 | unsigned int x; | 29 | unsigned int x; |
23 | 30 | ||
24 | x = ctrl_inl(0xfe410070 + offs); /* C0INITICI..CnINTICI */ | 31 | x = __raw_readl(0xfe410070 + offs); /* C0INITICI..CnINTICI */ |
25 | x &= (1 << (message << 2)); | 32 | x &= (1 << (message << 2)); |
26 | ctrl_outl(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */ | 33 | __raw_writel(x, 0xfe410080 + offs); /* C0INTICICLR..CnINTICICLR */ |
27 | 34 | ||
28 | smp_message_recv(message); | 35 | smp_message_recv(message); |
29 | 36 | ||
@@ -37,6 +44,9 @@ void __init plat_smp_setup(void) | |||
37 | 44 | ||
38 | init_cpu_possible(cpumask_of(cpu)); | 45 | init_cpu_possible(cpumask_of(cpu)); |
39 | 46 | ||
47 | /* Enable light sleep for the boot CPU */ | ||
48 | __raw_writel(__raw_readl(STBCR_REG(cpu)) | STBCR_LTSLP, STBCR_REG(cpu)); | ||
49 | |||
40 | __cpu_number_map[0] = 0; | 50 | __cpu_number_map[0] = 0; |
41 | __cpu_logical_map[0] = 0; | 51 | __cpu_logical_map[0] = 0; |
42 | 52 | ||
@@ -66,32 +76,23 @@ void __init plat_prepare_cpus(unsigned int max_cpus) | |||
66 | "IPI", (void *)(long)i); | 76 | "IPI", (void *)(long)i); |
67 | } | 77 | } |
68 | 78 | ||
69 | #define STBCR_REG(phys_id) (0xfe400004 | (phys_id << 12)) | ||
70 | #define RESET_REG(phys_id) (0xfe400008 | (phys_id << 12)) | ||
71 | |||
72 | #define STBCR_MSTP 0x00000001 | ||
73 | #define STBCR_RESET 0x00000002 | ||
74 | #define STBCR_LTSLP 0x80000000 | ||
75 | |||
76 | #define STBCR_AP_VAL (STBCR_RESET | STBCR_LTSLP) | ||
77 | |||
78 | void plat_start_cpu(unsigned int cpu, unsigned long entry_point) | 79 | void plat_start_cpu(unsigned int cpu, unsigned long entry_point) |
79 | { | 80 | { |
80 | ctrl_outl(entry_point, RESET_REG(cpu)); | 81 | __raw_writel(entry_point, RESET_REG(cpu)); |
81 | 82 | ||
82 | if (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) | 83 | if (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP)) |
83 | ctrl_outl(STBCR_MSTP, STBCR_REG(cpu)); | 84 | __raw_writel(STBCR_MSTP, STBCR_REG(cpu)); |
84 | 85 | ||
85 | while (!(ctrl_inl(STBCR_REG(cpu)) & STBCR_MSTP)) | 86 | while (!(__raw_readl(STBCR_REG(cpu)) & STBCR_MSTP)) |
86 | cpu_relax(); | 87 | cpu_relax(); |
87 | 88 | ||
88 | /* Start up secondary processor by sending a reset */ | 89 | /* Start up secondary processor by sending a reset */ |
89 | ctrl_outl(STBCR_AP_VAL, STBCR_REG(cpu)); | 90 | __raw_writel(STBCR_RESET | STBCR_LTSLP, STBCR_REG(cpu)); |
90 | } | 91 | } |
91 | 92 | ||
92 | int plat_smp_processor_id(void) | 93 | int plat_smp_processor_id(void) |
93 | { | 94 | { |
94 | return ctrl_inl(0xff000048); /* CPIDR */ | 95 | return __raw_readl(0xff000048); /* CPIDR */ |
95 | } | 96 | } |
96 | 97 | ||
97 | void plat_send_ipi(unsigned int cpu, unsigned int message) | 98 | void plat_send_ipi(unsigned int cpu, unsigned int message) |
@@ -100,5 +101,5 @@ void plat_send_ipi(unsigned int cpu, unsigned int message) | |||
100 | 101 | ||
101 | BUG_ON(cpu >= 4); | 102 | BUG_ON(cpu >= 4); |
102 | 103 | ||
103 | ctrl_outl(1 << (message << 2), addr); /* C0INTICI..CnINTICI */ | 104 | __raw_writel(1 << (message << 2), addr); /* C0INTICI..CnINTICI */ |
104 | } | 105 | } |
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S index b0aacf675258..8f13f73cb2cb 100644 --- a/arch/sh/kernel/cpu/sh5/entry.S +++ b/arch/sh/kernel/cpu/sh5/entry.S | |||
@@ -933,7 +933,7 @@ ret_with_reschedule: | |||
933 | 933 | ||
934 | pta restore_all, tr1 | 934 | pta restore_all, tr1 |
935 | 935 | ||
936 | movi (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r8 | 936 | movi _TIF_SIGPENDING, r8 |
937 | and r8, r7, r8 | 937 | and r8, r7, r8 |
938 | pta work_notifysig, tr0 | 938 | pta work_notifysig, tr0 |
939 | bne r8, ZERO, tr0 | 939 | bne r8, ZERO, tr0 |
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index 1c504bd972c3..83972aa319c2 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c | |||
@@ -87,25 +87,31 @@ void sh_mobile_setup_cpuidle(void) | |||
87 | 87 | ||
88 | dev->safe_state = state; | 88 | dev->safe_state = state; |
89 | 89 | ||
90 | state = &dev->states[i++]; | 90 | if (sh_mobile_sleep_supported & SUSP_SH_SF) { |
91 | snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); | 91 | state = &dev->states[i++]; |
92 | strncpy(state->desc, "SuperH Sleep Mode [SF]", CPUIDLE_DESC_LEN); | 92 | snprintf(state->name, CPUIDLE_NAME_LEN, "C1"); |
93 | state->exit_latency = 100; | 93 | strncpy(state->desc, "SuperH Sleep Mode [SF]", |
94 | state->target_residency = 1 * 2; | 94 | CPUIDLE_DESC_LEN); |
95 | state->power_usage = 1; | 95 | state->exit_latency = 100; |
96 | state->flags = 0; | 96 | state->target_residency = 1 * 2; |
97 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | 97 | state->power_usage = 1; |
98 | state->enter = cpuidle_sleep_enter; | 98 | state->flags = 0; |
99 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
100 | state->enter = cpuidle_sleep_enter; | ||
101 | } | ||
99 | 102 | ||
100 | state = &dev->states[i++]; | 103 | if (sh_mobile_sleep_supported & SUSP_SH_STANDBY) { |
101 | snprintf(state->name, CPUIDLE_NAME_LEN, "C2"); | 104 | state = &dev->states[i++]; |
102 | strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", CPUIDLE_DESC_LEN); | 105 | snprintf(state->name, CPUIDLE_NAME_LEN, "C2"); |
103 | state->exit_latency = 2300; | 106 | strncpy(state->desc, "SuperH Mobile Standby Mode [SF]", |
104 | state->target_residency = 1 * 2; | 107 | CPUIDLE_DESC_LEN); |
105 | state->power_usage = 1; | 108 | state->exit_latency = 2300; |
106 | state->flags = 0; | 109 | state->target_residency = 1 * 2; |
107 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | 110 | state->power_usage = 1; |
108 | state->enter = cpuidle_sleep_enter; | 111 | state->flags = 0; |
112 | state->flags |= CPUIDLE_FLAG_TIME_VALID; | ||
113 | state->enter = cpuidle_sleep_enter; | ||
114 | } | ||
109 | 115 | ||
110 | dev->state_count = i; | 116 | dev->state_count = i; |
111 | 117 | ||
diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c index ee3c2aaf66fb..ca029a44743c 100644 --- a/arch/sh/kernel/cpu/shmobile/pm.c +++ b/arch/sh/kernel/cpu/shmobile/pm.c | |||
@@ -15,6 +15,13 @@ | |||
15 | #include <linux/suspend.h> | 15 | #include <linux/suspend.h> |
16 | #include <asm/suspend.h> | 16 | #include <asm/suspend.h> |
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | #include <asm/cacheflush.h> | ||
19 | |||
20 | /* | ||
21 | * Notifier lists for pre/post sleep notification | ||
22 | */ | ||
23 | ATOMIC_NOTIFIER_HEAD(sh_mobile_pre_sleep_notifier_list); | ||
24 | ATOMIC_NOTIFIER_HEAD(sh_mobile_post_sleep_notifier_list); | ||
18 | 25 | ||
19 | /* | 26 | /* |
20 | * Sleep modes available on SuperH Mobile: | 27 | * Sleep modes available on SuperH Mobile: |
@@ -26,30 +33,105 @@ | |||
26 | #define SUSP_MODE_SLEEP (SUSP_SH_SLEEP) | 33 | #define SUSP_MODE_SLEEP (SUSP_SH_SLEEP) |
27 | #define SUSP_MODE_SLEEP_SF (SUSP_SH_SLEEP | SUSP_SH_SF) | 34 | #define SUSP_MODE_SLEEP_SF (SUSP_SH_SLEEP | SUSP_SH_SF) |
28 | #define SUSP_MODE_STANDBY_SF (SUSP_SH_STANDBY | SUSP_SH_SF) | 35 | #define SUSP_MODE_STANDBY_SF (SUSP_SH_STANDBY | SUSP_SH_SF) |
36 | #define SUSP_MODE_RSTANDBY (SUSP_SH_RSTANDBY | SUSP_SH_MMU | SUSP_SH_SF) | ||
37 | /* | ||
38 | * U-standby mode is unsupported since it needs bootloader hacks | ||
39 | */ | ||
29 | 40 | ||
30 | /* | 41 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 |
31 | * The following modes are not there yet: | 42 | #define RAM_BASE 0xfd800000 /* RSMEM */ |
32 | * | 43 | #else |
33 | * R-standby mode is unsupported, but will be added in the future | 44 | #define RAM_BASE 0xe5200000 /* ILRAM */ |
34 | * U-standby mode is low priority since it needs bootloader hacks | 45 | #endif |
35 | */ | ||
36 | |||
37 | #define ILRAM_BASE 0xe5200000 | ||
38 | |||
39 | extern const unsigned char sh_mobile_standby[]; | ||
40 | extern const unsigned int sh_mobile_standby_size; | ||
41 | 46 | ||
42 | void sh_mobile_call_standby(unsigned long mode) | 47 | void sh_mobile_call_standby(unsigned long mode) |
43 | { | 48 | { |
44 | void *onchip_mem = (void *)ILRAM_BASE; | 49 | void *onchip_mem = (void *)RAM_BASE; |
45 | void (*standby_onchip_mem)(unsigned long, unsigned long) = onchip_mem; | 50 | struct sh_sleep_data *sdp = onchip_mem; |
51 | void (*standby_onchip_mem)(unsigned long, unsigned long); | ||
52 | |||
53 | /* code located directly after data structure */ | ||
54 | standby_onchip_mem = (void *)(sdp + 1); | ||
55 | |||
56 | atomic_notifier_call_chain(&sh_mobile_pre_sleep_notifier_list, | ||
57 | mode, NULL); | ||
58 | |||
59 | /* flush the caches if MMU flag is set */ | ||
60 | if (mode & SUSP_SH_MMU) | ||
61 | flush_cache_all(); | ||
46 | 62 | ||
47 | /* Let assembly snippet in on-chip memory handle the rest */ | 63 | /* Let assembly snippet in on-chip memory handle the rest */ |
48 | standby_onchip_mem(mode, ILRAM_BASE); | 64 | standby_onchip_mem(mode, RAM_BASE); |
65 | |||
66 | atomic_notifier_call_chain(&sh_mobile_post_sleep_notifier_list, | ||
67 | mode, NULL); | ||
68 | } | ||
69 | |||
70 | extern char sh_mobile_sleep_enter_start; | ||
71 | extern char sh_mobile_sleep_enter_end; | ||
72 | |||
73 | extern char sh_mobile_sleep_resume_start; | ||
74 | extern char sh_mobile_sleep_resume_end; | ||
75 | |||
76 | unsigned long sh_mobile_sleep_supported = SUSP_SH_SLEEP; | ||
77 | |||
78 | void sh_mobile_register_self_refresh(unsigned long flags, | ||
79 | void *pre_start, void *pre_end, | ||
80 | void *post_start, void *post_end) | ||
81 | { | ||
82 | void *onchip_mem = (void *)RAM_BASE; | ||
83 | void *vp; | ||
84 | struct sh_sleep_data *sdp; | ||
85 | int n; | ||
86 | |||
87 | /* part 0: data area */ | ||
88 | sdp = onchip_mem; | ||
89 | sdp->addr.stbcr = 0xa4150020; /* STBCR */ | ||
90 | sdp->addr.bar = 0xa4150040; /* BAR */ | ||
91 | sdp->addr.pteh = 0xff000000; /* PTEH */ | ||
92 | sdp->addr.ptel = 0xff000004; /* PTEL */ | ||
93 | sdp->addr.ttb = 0xff000008; /* TTB */ | ||
94 | sdp->addr.tea = 0xff00000c; /* TEA */ | ||
95 | sdp->addr.mmucr = 0xff000010; /* MMUCR */ | ||
96 | sdp->addr.ptea = 0xff000034; /* PTEA */ | ||
97 | sdp->addr.pascr = 0xff000070; /* PASCR */ | ||
98 | sdp->addr.irmcr = 0xff000078; /* IRMCR */ | ||
99 | sdp->addr.ccr = 0xff00001c; /* CCR */ | ||
100 | sdp->addr.ramcr = 0xff000074; /* RAMCR */ | ||
101 | vp = sdp + 1; | ||
102 | |||
103 | /* part 1: common code to enter sleep mode */ | ||
104 | n = &sh_mobile_sleep_enter_end - &sh_mobile_sleep_enter_start; | ||
105 | memcpy(vp, &sh_mobile_sleep_enter_start, n); | ||
106 | vp += roundup(n, 4); | ||
107 | |||
108 | /* part 2: board specific code to enter self-refresh mode */ | ||
109 | n = pre_end - pre_start; | ||
110 | memcpy(vp, pre_start, n); | ||
111 | sdp->sf_pre = (unsigned long)vp; | ||
112 | vp += roundup(n, 4); | ||
113 | |||
114 | /* part 3: board specific code to resume from self-refresh mode */ | ||
115 | n = post_end - post_start; | ||
116 | memcpy(vp, post_start, n); | ||
117 | sdp->sf_post = (unsigned long)vp; | ||
118 | vp += roundup(n, 4); | ||
119 | |||
120 | /* part 4: common code to resume from sleep mode */ | ||
121 | WARN_ON(vp > (onchip_mem + 0x600)); | ||
122 | vp = onchip_mem + 0x600; /* located at interrupt vector */ | ||
123 | n = &sh_mobile_sleep_resume_end - &sh_mobile_sleep_resume_start; | ||
124 | memcpy(vp, &sh_mobile_sleep_resume_start, n); | ||
125 | sdp->resume = (unsigned long)vp; | ||
126 | |||
127 | sh_mobile_sleep_supported |= flags; | ||
49 | } | 128 | } |
50 | 129 | ||
51 | static int sh_pm_enter(suspend_state_t state) | 130 | static int sh_pm_enter(suspend_state_t state) |
52 | { | 131 | { |
132 | if (!(sh_mobile_sleep_supported & SUSP_MODE_STANDBY_SF)) | ||
133 | return -ENXIO; | ||
134 | |||
53 | local_irq_disable(); | 135 | local_irq_disable(); |
54 | set_bl_bit(); | 136 | set_bl_bit(); |
55 | sh_mobile_call_standby(SUSP_MODE_STANDBY_SF); | 137 | sh_mobile_call_standby(SUSP_MODE_STANDBY_SF); |
@@ -65,13 +147,6 @@ static struct platform_suspend_ops sh_pm_ops = { | |||
65 | 147 | ||
66 | static int __init sh_pm_init(void) | 148 | static int __init sh_pm_init(void) |
67 | { | 149 | { |
68 | void *onchip_mem = (void *)ILRAM_BASE; | ||
69 | |||
70 | /* Copy the assembly snippet to the otherwise ununsed ILRAM */ | ||
71 | memcpy(onchip_mem, sh_mobile_standby, sh_mobile_standby_size); | ||
72 | wmb(); | ||
73 | ctrl_barrier(); | ||
74 | |||
75 | suspend_set_ops(&sh_pm_ops); | 150 | suspend_set_ops(&sh_pm_ops); |
76 | sh_mobile_setup_cpuidle(); | 151 | sh_mobile_setup_cpuidle(); |
77 | return 0; | 152 | return 0; |
diff --git a/arch/sh/kernel/cpu/shmobile/pm_runtime.c b/arch/sh/kernel/cpu/shmobile/pm_runtime.c index 7c615b17e209..6dcb8166a64d 100644 --- a/arch/sh/kernel/cpu/shmobile/pm_runtime.c +++ b/arch/sh/kernel/cpu/shmobile/pm_runtime.c | |||
@@ -45,12 +45,14 @@ static int __platform_pm_runtime_resume(struct platform_device *pdev) | |||
45 | 45 | ||
46 | dev_dbg(d, "__platform_pm_runtime_resume() [%d]\n", hwblk); | 46 | dev_dbg(d, "__platform_pm_runtime_resume() [%d]\n", hwblk); |
47 | 47 | ||
48 | if (d->driver && d->driver->pm && d->driver->pm->runtime_resume) { | 48 | if (d->driver) { |
49 | hwblk_enable(hwblk_info, hwblk); | 49 | hwblk_enable(hwblk_info, hwblk); |
50 | ret = 0; | 50 | ret = 0; |
51 | 51 | ||
52 | if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) { | 52 | if (test_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags)) { |
53 | ret = d->driver->pm->runtime_resume(d); | 53 | if (d->driver->pm && d->driver->pm->runtime_resume) |
54 | ret = d->driver->pm->runtime_resume(d); | ||
55 | |||
54 | if (!ret) | 56 | if (!ret) |
55 | clear_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); | 57 | clear_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); |
56 | else | 58 | else |
@@ -73,12 +75,15 @@ static int __platform_pm_runtime_suspend(struct platform_device *pdev) | |||
73 | 75 | ||
74 | dev_dbg(d, "__platform_pm_runtime_suspend() [%d]\n", hwblk); | 76 | dev_dbg(d, "__platform_pm_runtime_suspend() [%d]\n", hwblk); |
75 | 77 | ||
76 | if (d->driver && d->driver->pm && d->driver->pm->runtime_suspend) { | 78 | if (d->driver) { |
77 | BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags)); | 79 | BUG_ON(!test_bit(PDEV_ARCHDATA_FLAG_IDLE, &ad->flags)); |
80 | ret = 0; | ||
78 | 81 | ||
79 | hwblk_enable(hwblk_info, hwblk); | 82 | if (d->driver->pm && d->driver->pm->runtime_suspend) { |
80 | ret = d->driver->pm->runtime_suspend(d); | 83 | hwblk_enable(hwblk_info, hwblk); |
81 | hwblk_disable(hwblk_info, hwblk); | 84 | ret = d->driver->pm->runtime_suspend(d); |
85 | hwblk_disable(hwblk_info, hwblk); | ||
86 | } | ||
82 | 87 | ||
83 | if (!ret) { | 88 | if (!ret) { |
84 | set_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); | 89 | set_bit(PDEV_ARCHDATA_FLAG_SUSP, &ad->flags); |
diff --git a/arch/sh/kernel/cpu/shmobile/sleep.S b/arch/sh/kernel/cpu/shmobile/sleep.S index a439e6c7824f..e9dd7fa0abd2 100644 --- a/arch/sh/kernel/cpu/shmobile/sleep.S +++ b/arch/sh/kernel/cpu/shmobile/sleep.S | |||
@@ -20,79 +20,103 @@ | |||
20 | * Kernel mode register usage, see entry.S: | 20 | * Kernel mode register usage, see entry.S: |
21 | * k0 scratch | 21 | * k0 scratch |
22 | * k1 scratch | 22 | * k1 scratch |
23 | * k4 scratch | ||
24 | */ | 23 | */ |
25 | #define k0 r0 | 24 | #define k0 r0 |
26 | #define k1 r1 | 25 | #define k1 r1 |
27 | #define k4 r4 | ||
28 | 26 | ||
29 | /* manage self-refresh and enter standby mode. | 27 | /* manage self-refresh and enter standby mode. must be self-contained. |
30 | * this code will be copied to on-chip memory and executed from there. | 28 | * this code will be copied to on-chip memory and executed from there. |
31 | */ | 29 | */ |
30 | .balign 4 | ||
31 | ENTRY(sh_mobile_sleep_enter_start) | ||
32 | 32 | ||
33 | .balign 4096,0,4096 | 33 | /* save mode flags */ |
34 | ENTRY(sh_mobile_standby) | 34 | mov.l r4, @(SH_SLEEP_MODE, r5) |
35 | 35 | ||
36 | /* save original vbr */ | 36 | /* save original vbr */ |
37 | stc vbr, r1 | 37 | stc vbr, r0 |
38 | mova saved_vbr, r0 | 38 | mov.l r0, @(SH_SLEEP_VBR, r5) |
39 | mov.l r1, @r0 | ||
40 | 39 | ||
41 | /* point vbr to our on-chip memory page */ | 40 | /* point vbr to our on-chip memory page */ |
42 | ldc r5, vbr | 41 | ldc r5, vbr |
43 | 42 | ||
44 | /* save return address */ | 43 | /* save return address */ |
45 | mova saved_spc, r0 | 44 | sts pr, r0 |
46 | sts pr, r5 | 45 | mov.l r0, @(SH_SLEEP_SPC, r5) |
47 | mov.l r5, @r0 | ||
48 | 46 | ||
49 | /* save sr */ | 47 | /* save sr */ |
50 | mova saved_sr, r0 | 48 | stc sr, r0 |
51 | stc sr, r5 | 49 | mov.l r0, @(SH_SLEEP_SR, r5) |
52 | mov.l r5, @r0 | ||
53 | 50 | ||
54 | /* save mode flags */ | 51 | /* save sp */ |
55 | mova saved_mode, r0 | 52 | mov.l r15, @(SH_SLEEP_SP, r5) |
56 | mov.l r4, @r0 | 53 | |
54 | /* save stbcr */ | ||
55 | bsr save_register | ||
56 | mov #SH_SLEEP_REG_STBCR, r0 | ||
57 | |||
58 | /* save mmu and cache context if needed */ | ||
59 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
60 | tst #SUSP_SH_MMU, r0 | ||
61 | bt skip_mmu_save_disable | ||
62 | |||
63 | /* save mmu state */ | ||
64 | bsr save_register | ||
65 | mov #SH_SLEEP_REG_PTEH, r0 | ||
66 | |||
67 | bsr save_register | ||
68 | mov #SH_SLEEP_REG_PTEL, r0 | ||
69 | |||
70 | bsr save_register | ||
71 | mov #SH_SLEEP_REG_TTB, r0 | ||
72 | |||
73 | bsr save_register | ||
74 | mov #SH_SLEEP_REG_TEA, r0 | ||
75 | |||
76 | bsr save_register | ||
77 | mov #SH_SLEEP_REG_MMUCR, r0 | ||
78 | |||
79 | bsr save_register | ||
80 | mov #SH_SLEEP_REG_PTEA, r0 | ||
81 | |||
82 | bsr save_register | ||
83 | mov #SH_SLEEP_REG_PASCR, r0 | ||
57 | 84 | ||
58 | /* put mode flags in r0 */ | 85 | bsr save_register |
59 | mov r4, r0 | 86 | mov #SH_SLEEP_REG_IRMCR, r0 |
60 | 87 | ||
88 | /* invalidate TLBs and disable the MMU */ | ||
89 | bsr get_register | ||
90 | mov #SH_SLEEP_REG_MMUCR, r0 | ||
91 | mov #4, r1 | ||
92 | mov.l r1, @r0 | ||
93 | icbi @r0 | ||
94 | |||
95 | /* save cache registers and disable caches */ | ||
96 | bsr save_register | ||
97 | mov #SH_SLEEP_REG_CCR, r0 | ||
98 | |||
99 | bsr save_register | ||
100 | mov #SH_SLEEP_REG_RAMCR, r0 | ||
101 | |||
102 | bsr get_register | ||
103 | mov #SH_SLEEP_REG_CCR, r0 | ||
104 | mov #0, r1 | ||
105 | mov.l r1, @r0 | ||
106 | icbi @r0 | ||
107 | |||
108 | skip_mmu_save_disable: | ||
109 | /* call self-refresh entering code if needed */ | ||
110 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
61 | tst #SUSP_SH_SF, r0 | 111 | tst #SUSP_SH_SF, r0 |
62 | bt skip_set_sf | 112 | bt skip_set_sf |
63 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 | 113 | |
64 | /* DBSC: put memory in self-refresh mode */ | 114 | mov.l @(SH_SLEEP_SF_PRE, r5), r0 |
65 | mov.l dben_reg, r4 | 115 | jsr @r0 |
66 | mov.l dben_data0, r1 | 116 | nop |
67 | mov.l r1, @r4 | ||
68 | |||
69 | mov.l dbrfpdn0_reg, r4 | ||
70 | mov.l dbrfpdn0_data0, r1 | ||
71 | mov.l r1, @r4 | ||
72 | |||
73 | mov.l dbcmdcnt_reg, r4 | ||
74 | mov.l dbcmdcnt_data0, r1 | ||
75 | mov.l r1, @r4 | ||
76 | |||
77 | mov.l dbcmdcnt_reg, r4 | ||
78 | mov.l dbcmdcnt_data1, r1 | ||
79 | mov.l r1, @r4 | ||
80 | |||
81 | mov.l dbrfpdn0_reg, r4 | ||
82 | mov.l dbrfpdn0_data1, r1 | ||
83 | mov.l r1, @r4 | ||
84 | #else | ||
85 | /* SBSC: disable power down and put in self-refresh mode */ | ||
86 | mov.l 1f, r4 | ||
87 | mov.l 2f, r1 | ||
88 | mov.l @r4, r2 | ||
89 | or r1, r2 | ||
90 | mov.l 3f, r3 | ||
91 | and r3, r2 | ||
92 | mov.l r2, @r4 | ||
93 | #endif | ||
94 | 117 | ||
95 | skip_set_sf: | 118 | skip_set_sf: |
119 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
96 | tst #SUSP_SH_STANDBY, r0 | 120 | tst #SUSP_SH_STANDBY, r0 |
97 | bt test_rstandby | 121 | bt test_rstandby |
98 | 122 | ||
@@ -104,6 +128,12 @@ test_rstandby: | |||
104 | tst #SUSP_SH_RSTANDBY, r0 | 128 | tst #SUSP_SH_RSTANDBY, r0 |
105 | bt test_ustandby | 129 | bt test_ustandby |
106 | 130 | ||
131 | /* setup BAR register */ | ||
132 | bsr get_register | ||
133 | mov #SH_SLEEP_REG_BAR, r0 | ||
134 | mov.l @(SH_SLEEP_RESUME, r5), r1 | ||
135 | mov.l r1, @r0 | ||
136 | |||
107 | /* set mode to "r-standby mode" */ | 137 | /* set mode to "r-standby mode" */ |
108 | bra do_sleep | 138 | bra do_sleep |
109 | mov #0x20, r1 | 139 | mov #0x20, r1 |
@@ -123,124 +153,136 @@ force_sleep: | |||
123 | 153 | ||
124 | do_sleep: | 154 | do_sleep: |
125 | /* setup and enter selected standby mode */ | 155 | /* setup and enter selected standby mode */ |
126 | mov.l 5f, r4 | 156 | bsr get_register |
127 | mov.l r1, @r4 | 157 | mov #SH_SLEEP_REG_STBCR, r0 |
158 | mov.l r1, @r0 | ||
128 | again: | 159 | again: |
129 | sleep | 160 | sleep |
130 | bra again | 161 | bra again |
131 | nop | 162 | nop |
132 | 163 | ||
133 | restore_jump_vbr: | 164 | save_register: |
165 | add #SH_SLEEP_BASE_ADDR, r0 | ||
166 | mov.l @(r0, r5), r1 | ||
167 | add #-SH_SLEEP_BASE_ADDR, r0 | ||
168 | mov.l @r1, r1 | ||
169 | add #SH_SLEEP_BASE_DATA, r0 | ||
170 | mov.l r1, @(r0, r5) | ||
171 | add #-SH_SLEEP_BASE_DATA, r0 | ||
172 | rts | ||
173 | nop | ||
174 | |||
175 | get_register: | ||
176 | add #SH_SLEEP_BASE_ADDR, r0 | ||
177 | mov.l @(r0, r5), r0 | ||
178 | rts | ||
179 | nop | ||
180 | ENTRY(sh_mobile_sleep_enter_end) | ||
181 | |||
182 | .balign 4 | ||
183 | ENTRY(sh_mobile_sleep_resume_start) | ||
184 | |||
185 | /* figure out start address */ | ||
186 | bsr 0f | ||
187 | nop | ||
188 | 0: | ||
189 | sts pr, k1 | ||
190 | mov.l 1f, k0 | ||
191 | and k0, k1 | ||
192 | |||
193 | /* store pointer to data area in VBR */ | ||
194 | ldc k1, vbr | ||
195 | |||
196 | /* setup sr with saved sr */ | ||
197 | mov.l @(SH_SLEEP_SR, k1), k0 | ||
198 | ldc k0, sr | ||
199 | |||
200 | /* now: user register set! */ | ||
201 | stc vbr, r5 | ||
202 | |||
134 | /* setup spc with return address to c code */ | 203 | /* setup spc with return address to c code */ |
135 | mov.l saved_spc, k0 | 204 | mov.l @(SH_SLEEP_SPC, r5), r0 |
136 | ldc k0, spc | 205 | ldc r0, spc |
137 | 206 | ||
138 | /* restore vbr */ | 207 | /* restore vbr */ |
139 | mov.l saved_vbr, k0 | 208 | mov.l @(SH_SLEEP_VBR, r5), r0 |
140 | ldc k0, vbr | 209 | ldc r0, vbr |
141 | 210 | ||
142 | /* setup ssr with saved sr */ | 211 | /* setup ssr with saved sr */ |
143 | mov.l saved_sr, k0 | 212 | mov.l @(SH_SLEEP_SR, r5), r0 |
144 | ldc k0, ssr | 213 | ldc r0, ssr |
145 | 214 | ||
146 | /* get mode flags */ | 215 | /* restore sp */ |
147 | mov.l saved_mode, k0 | 216 | mov.l @(SH_SLEEP_SP, r5), r15 |
148 | 217 | ||
149 | done_sleep: | 218 | /* restore sleep mode register */ |
150 | /* reset standby mode to sleep mode */ | 219 | bsr restore_register |
151 | mov.l 5f, k4 | 220 | mov #SH_SLEEP_REG_STBCR, r0 |
152 | mov #0x00, k1 | ||
153 | mov.l k1, @k4 | ||
154 | 221 | ||
155 | tst #SUSP_SH_SF, k0 | 222 | /* call self-refresh resume code if needed */ |
223 | mov.l @(SH_SLEEP_MODE, r5), r0 | ||
224 | tst #SUSP_SH_SF, r0 | ||
156 | bt skip_restore_sf | 225 | bt skip_restore_sf |
157 | 226 | ||
158 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 | 227 | mov.l @(SH_SLEEP_SF_POST, r5), r0 |
159 | /* DBSC: put memory in auto-refresh mode */ | 228 | jsr @r0 |
160 | mov.l dbrfpdn0_reg, k4 | 229 | nop |
161 | mov.l dbrfpdn0_data0, k1 | 230 | |
162 | mov.l k1, @k4 | ||
163 | |||
164 | nop /* sleep 140 ns */ | ||
165 | nop | ||
166 | nop | ||
167 | nop | ||
168 | |||
169 | mov.l dbcmdcnt_reg, k4 | ||
170 | mov.l dbcmdcnt_data0, k1 | ||
171 | mov.l k1, @k4 | ||
172 | |||
173 | mov.l dbcmdcnt_reg, k4 | ||
174 | mov.l dbcmdcnt_data1, k1 | ||
175 | mov.l k1, @k4 | ||
176 | |||
177 | mov.l dben_reg, k4 | ||
178 | mov.l dben_data1, k1 | ||
179 | mov.l k1, @k4 | ||
180 | |||
181 | mov.l dbrfpdn0_reg, k4 | ||
182 | mov.l dbrfpdn0_data2, k1 | ||
183 | mov.l k1, @k4 | ||
184 | #else | ||
185 | /* SBSC: set auto-refresh mode */ | ||
186 | mov.l 1f, k4 | ||
187 | mov.l @k4, k0 | ||
188 | mov.l 4f, k1 | ||
189 | and k1, k0 | ||
190 | mov.l k0, @k4 | ||
191 | mov.l 6f, k4 | ||
192 | mov.l 8f, k0 | ||
193 | mov.l @k4, k1 | ||
194 | mov #-1, k4 | ||
195 | add k4, k1 | ||
196 | or k1, k0 | ||
197 | mov.l 7f, k1 | ||
198 | mov.l k0, @k1 | ||
199 | #endif | ||
200 | skip_restore_sf: | 231 | skip_restore_sf: |
201 | /* jump to vbr vector */ | 232 | /* restore mmu and cache state if needed */ |
202 | mov.l saved_vbr, k0 | 233 | mov.l @(SH_SLEEP_MODE, r5), r0 |
203 | mov.l offset_vbr, k4 | 234 | tst #SUSP_SH_MMU, r0 |
204 | add k4, k0 | 235 | bt skip_restore_mmu |
205 | jmp @k0 | 236 | |
237 | /* restore mmu state */ | ||
238 | bsr restore_register | ||
239 | mov #SH_SLEEP_REG_PTEH, r0 | ||
240 | |||
241 | bsr restore_register | ||
242 | mov #SH_SLEEP_REG_PTEL, r0 | ||
243 | |||
244 | bsr restore_register | ||
245 | mov #SH_SLEEP_REG_TTB, r0 | ||
246 | |||
247 | bsr restore_register | ||
248 | mov #SH_SLEEP_REG_TEA, r0 | ||
249 | |||
250 | bsr restore_register | ||
251 | mov #SH_SLEEP_REG_PTEA, r0 | ||
252 | |||
253 | bsr restore_register | ||
254 | mov #SH_SLEEP_REG_PASCR, r0 | ||
255 | |||
256 | bsr restore_register | ||
257 | mov #SH_SLEEP_REG_IRMCR, r0 | ||
258 | |||
259 | bsr restore_register | ||
260 | mov #SH_SLEEP_REG_MMUCR, r0 | ||
261 | icbi @r0 | ||
262 | |||
263 | /* restore cache settings */ | ||
264 | bsr restore_register | ||
265 | mov #SH_SLEEP_REG_RAMCR, r0 | ||
266 | icbi @r0 | ||
267 | |||
268 | bsr restore_register | ||
269 | mov #SH_SLEEP_REG_CCR, r0 | ||
270 | icbi @r0 | ||
271 | |||
272 | skip_restore_mmu: | ||
273 | rte | ||
206 | nop | 274 | nop |
207 | 275 | ||
208 | .balign 4 | 276 | restore_register: |
209 | saved_mode: .long 0 | 277 | add #SH_SLEEP_BASE_DATA, r0 |
210 | saved_spc: .long 0 | 278 | mov.l @(r0, r5), r1 |
211 | saved_sr: .long 0 | 279 | add #-SH_SLEEP_BASE_DATA, r0 |
212 | saved_vbr: .long 0 | 280 | add #SH_SLEEP_BASE_ADDR, r0 |
213 | offset_vbr: .long 0x600 | 281 | mov.l @(r0, r5), r0 |
214 | #ifdef CONFIG_CPU_SUBTYPE_SH7724 | 282 | mov.l r1, @r0 |
215 | dben_reg: .long 0xfd000010 /* DBEN */ | 283 | rts |
216 | dben_data0: .long 0 | ||
217 | dben_data1: .long 1 | ||
218 | dbrfpdn0_reg: .long 0xfd000040 /* DBRFPDN0 */ | ||
219 | dbrfpdn0_data0: .long 0 | ||
220 | dbrfpdn0_data1: .long 1 | ||
221 | dbrfpdn0_data2: .long 0x00010000 | ||
222 | dbcmdcnt_reg: .long 0xfd000014 /* DBCMDCNT */ | ||
223 | dbcmdcnt_data0: .long 2 | ||
224 | dbcmdcnt_data1: .long 4 | ||
225 | #else | ||
226 | 1: .long 0xfe400008 /* SDCR0 */ | ||
227 | 2: .long 0x00000400 | ||
228 | 3: .long 0xffff7fff | ||
229 | 4: .long 0xfffffbff | ||
230 | #endif | ||
231 | 5: .long 0xa4150020 /* STBCR */ | ||
232 | 6: .long 0xfe40001c /* RTCOR */ | ||
233 | 7: .long 0xfe400018 /* RTCNT */ | ||
234 | 8: .long 0xa55a0000 | ||
235 | |||
236 | |||
237 | /* interrupt vector @ 0x600 */ | ||
238 | .balign 0x400,0,0x400 | ||
239 | .long 0xdeadbeef | ||
240 | .balign 0x200,0,0x200 | ||
241 | bra restore_jump_vbr | ||
242 | nop | 284 | nop |
243 | sh_mobile_standby_end: | ||
244 | 285 | ||
245 | ENTRY(sh_mobile_standby_size) | 286 | .balign 4 |
246 | .long sh_mobile_standby_end - sh_mobile_standby | 287 | 1: .long ~0x7ff |
288 | ENTRY(sh_mobile_sleep_resume_end) | ||
diff --git a/arch/sh/kernel/cpu/ubc.S b/arch/sh/kernel/cpu/ubc.S deleted file mode 100644 index 81923079fa12..000000000000 --- a/arch/sh/kernel/cpu/ubc.S +++ /dev/null | |||
@@ -1,59 +0,0 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/cpu/ubc.S | ||
3 | * | ||
4 | * Set of management routines for the User Break Controller (UBC) | ||
5 | * | ||
6 | * Copyright (C) 2002 Paul Mundt | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | #include <linux/linkage.h> | ||
14 | #include <asm/ubc.h> | ||
15 | |||
16 | #define STBCR2 0xffc00010 | ||
17 | |||
18 | ENTRY(ubc_sleep) | ||
19 | mov #0, r0 | ||
20 | |||
21 | mov.l 1f, r1 ! Zero out UBC_BBRA .. | ||
22 | mov.w r0, @r1 | ||
23 | |||
24 | mov.l 2f, r1 ! .. same for BBRB .. | ||
25 | mov.w r0, @r1 | ||
26 | |||
27 | mov.l 3f, r1 ! .. and again for BRCR. | ||
28 | mov.w r0, @r1 | ||
29 | |||
30 | mov.w @r1, r0 ! Dummy read BRCR | ||
31 | |||
32 | mov.l 4f, r1 ! Set MSTP5 in STBCR2 | ||
33 | mov.b @r1, r0 | ||
34 | or #0x01, r0 | ||
35 | mov.b r0, @r1 | ||
36 | |||
37 | mov.b @r1, r0 ! Two dummy reads .. | ||
38 | mov.b @r1, r0 | ||
39 | |||
40 | rts | ||
41 | nop | ||
42 | |||
43 | ENTRY(ubc_wakeup) | ||
44 | mov.l 4f, r1 ! Clear MSTP5 | ||
45 | mov.b @r1, r0 | ||
46 | and #0xfe, r0 | ||
47 | mov.b r0, @r1 | ||
48 | |||
49 | mov.b @r1, r0 ! Two more dummy reads .. | ||
50 | mov.b @r1, r0 | ||
51 | |||
52 | rts | ||
53 | nop | ||
54 | |||
55 | 1: .long UBC_BBRA | ||
56 | 2: .long UBC_BBRB | ||
57 | 3: .long UBC_BRCR | ||
58 | 4: .long STBCR2 | ||
59 | |||
diff --git a/arch/sh/kernel/dma-nommu.c b/arch/sh/kernel/dma-nommu.c new file mode 100644 index 000000000000..3c55b87f8b63 --- /dev/null +++ b/arch/sh/kernel/dma-nommu.c | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * DMA mapping support for platforms lacking IOMMUs. | ||
3 | * | ||
4 | * Copyright (C) 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/dma-mapping.h> | ||
11 | #include <linux/io.h> | ||
12 | |||
13 | static dma_addr_t nommu_map_page(struct device *dev, struct page *page, | ||
14 | unsigned long offset, size_t size, | ||
15 | enum dma_data_direction dir, | ||
16 | struct dma_attrs *attrs) | ||
17 | { | ||
18 | dma_addr_t addr = page_to_phys(page) + offset; | ||
19 | |||
20 | WARN_ON(size == 0); | ||
21 | dma_cache_sync(dev, page_address(page) + offset, size, dir); | ||
22 | |||
23 | return addr; | ||
24 | } | ||
25 | |||
26 | static int nommu_map_sg(struct device *dev, struct scatterlist *sg, | ||
27 | int nents, enum dma_data_direction dir, | ||
28 | struct dma_attrs *attrs) | ||
29 | { | ||
30 | struct scatterlist *s; | ||
31 | int i; | ||
32 | |||
33 | WARN_ON(nents == 0 || sg[0].length == 0); | ||
34 | |||
35 | for_each_sg(sg, s, nents, i) { | ||
36 | BUG_ON(!sg_page(s)); | ||
37 | |||
38 | dma_cache_sync(dev, sg_virt(s), s->length, dir); | ||
39 | |||
40 | s->dma_address = sg_phys(s); | ||
41 | s->dma_length = s->length; | ||
42 | } | ||
43 | |||
44 | return nents; | ||
45 | } | ||
46 | |||
47 | #ifdef CONFIG_DMA_NONCOHERENT | ||
48 | static void nommu_sync_single(struct device *dev, dma_addr_t addr, | ||
49 | size_t size, enum dma_data_direction dir) | ||
50 | { | ||
51 | dma_cache_sync(dev, phys_to_virt(addr), size, dir); | ||
52 | } | ||
53 | |||
54 | static void nommu_sync_sg(struct device *dev, struct scatterlist *sg, | ||
55 | int nelems, enum dma_data_direction dir) | ||
56 | { | ||
57 | struct scatterlist *s; | ||
58 | int i; | ||
59 | |||
60 | for_each_sg(sg, s, nelems, i) | ||
61 | dma_cache_sync(dev, sg_virt(s), s->length, dir); | ||
62 | } | ||
63 | #endif | ||
64 | |||
65 | struct dma_map_ops nommu_dma_ops = { | ||
66 | .alloc_coherent = dma_generic_alloc_coherent, | ||
67 | .free_coherent = dma_generic_free_coherent, | ||
68 | .map_page = nommu_map_page, | ||
69 | .map_sg = nommu_map_sg, | ||
70 | #ifdef CONFIG_DMA_NONCOHERENT | ||
71 | .sync_single_for_device = nommu_sync_single, | ||
72 | .sync_sg_for_device = nommu_sync_sg, | ||
73 | #endif | ||
74 | .is_phys = 1, | ||
75 | }; | ||
76 | |||
77 | void __init no_iommu_init(void) | ||
78 | { | ||
79 | if (dma_ops) | ||
80 | return; | ||
81 | dma_ops = &nommu_dma_ops; | ||
82 | } | ||
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index d76a23170dbb..3576b709f052 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/list.h> | 20 | #include <linux/list.h> |
21 | #include <linux/mempool.h> | 21 | #include <linux/mempool.h> |
22 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
23 | #include <linux/elf.h> | ||
23 | #include <linux/ftrace.h> | 24 | #include <linux/ftrace.h> |
24 | #include <asm/dwarf.h> | 25 | #include <asm/dwarf.h> |
25 | #include <asm/unwinder.h> | 26 | #include <asm/unwinder.h> |
@@ -530,7 +531,18 @@ static int dwarf_cfa_execute_insns(unsigned char *insn_start, | |||
530 | } | 531 | } |
531 | 532 | ||
532 | /** | 533 | /** |
533 | * dwarf_unwind_stack - recursively unwind the stack | 534 | * dwarf_free_frame - free the memory allocated for @frame |
535 | * @frame: the frame to free | ||
536 | */ | ||
537 | void dwarf_free_frame(struct dwarf_frame *frame) | ||
538 | { | ||
539 | dwarf_frame_free_regs(frame); | ||
540 | mempool_free(frame, dwarf_frame_pool); | ||
541 | } | ||
542 | |||
543 | /** | ||
544 | * dwarf_unwind_stack - unwind the stack | ||
545 | * | ||
534 | * @pc: address of the function to unwind | 546 | * @pc: address of the function to unwind |
535 | * @prev: struct dwarf_frame of the previous stackframe on the callstack | 547 | * @prev: struct dwarf_frame of the previous stackframe on the callstack |
536 | * | 548 | * |
@@ -548,9 +560,9 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc, | |||
548 | unsigned long addr; | 560 | unsigned long addr; |
549 | 561 | ||
550 | /* | 562 | /* |
551 | * If this is the first invocation of this recursive function we | 563 | * If we're starting at the top of the stack we need get the |
552 | * need get the contents of a physical register to get the CFA | 564 | * contents of a physical register to get the CFA in order to |
553 | * in order to begin the virtual unwinding of the stack. | 565 | * begin the virtual unwinding of the stack. |
554 | * | 566 | * |
555 | * NOTE: the return address is guaranteed to be setup by the | 567 | * NOTE: the return address is guaranteed to be setup by the |
556 | * time this function makes its first function call. | 568 | * time this function makes its first function call. |
@@ -593,9 +605,8 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc, | |||
593 | fde = dwarf_lookup_fde(pc); | 605 | fde = dwarf_lookup_fde(pc); |
594 | if (!fde) { | 606 | if (!fde) { |
595 | /* | 607 | /* |
596 | * This is our normal exit path - the one that stops the | 608 | * This is our normal exit path. There are two reasons |
597 | * recursion. There's two reasons why we might exit | 609 | * why we might exit here, |
598 | * here, | ||
599 | * | 610 | * |
600 | * a) pc has no asscociated DWARF frame info and so | 611 | * a) pc has no asscociated DWARF frame info and so |
601 | * we don't know how to unwind this frame. This is | 612 | * we don't know how to unwind this frame. This is |
@@ -637,10 +648,10 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc, | |||
637 | 648 | ||
638 | } else { | 649 | } else { |
639 | /* | 650 | /* |
640 | * Again, this is the first invocation of this | 651 | * Again, we're starting from the top of the |
641 | * recurisve function. We need to physically | 652 | * stack. We need to physically read |
642 | * read the contents of a register in order to | 653 | * the contents of a register in order to get |
643 | * get the Canonical Frame Address for this | 654 | * the Canonical Frame Address for this |
644 | * function. | 655 | * function. |
645 | */ | 656 | */ |
646 | frame->cfa = dwarf_read_arch_reg(frame->cfa_register); | 657 | frame->cfa = dwarf_read_arch_reg(frame->cfa_register); |
@@ -670,13 +681,12 @@ struct dwarf_frame * dwarf_unwind_stack(unsigned long pc, | |||
670 | return frame; | 681 | return frame; |
671 | 682 | ||
672 | bail: | 683 | bail: |
673 | dwarf_frame_free_regs(frame); | 684 | dwarf_free_frame(frame); |
674 | mempool_free(frame, dwarf_frame_pool); | ||
675 | return NULL; | 685 | return NULL; |
676 | } | 686 | } |
677 | 687 | ||
678 | static int dwarf_parse_cie(void *entry, void *p, unsigned long len, | 688 | static int dwarf_parse_cie(void *entry, void *p, unsigned long len, |
679 | unsigned char *end) | 689 | unsigned char *end, struct module *mod) |
680 | { | 690 | { |
681 | struct dwarf_cie *cie; | 691 | struct dwarf_cie *cie; |
682 | unsigned long flags; | 692 | unsigned long flags; |
@@ -772,6 +782,8 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len, | |||
772 | cie->initial_instructions = p; | 782 | cie->initial_instructions = p; |
773 | cie->instructions_end = end; | 783 | cie->instructions_end = end; |
774 | 784 | ||
785 | cie->mod = mod; | ||
786 | |||
775 | /* Add to list */ | 787 | /* Add to list */ |
776 | spin_lock_irqsave(&dwarf_cie_lock, flags); | 788 | spin_lock_irqsave(&dwarf_cie_lock, flags); |
777 | list_add_tail(&cie->link, &dwarf_cie_list); | 789 | list_add_tail(&cie->link, &dwarf_cie_list); |
@@ -782,7 +794,7 @@ static int dwarf_parse_cie(void *entry, void *p, unsigned long len, | |||
782 | 794 | ||
783 | static int dwarf_parse_fde(void *entry, u32 entry_type, | 795 | static int dwarf_parse_fde(void *entry, u32 entry_type, |
784 | void *start, unsigned long len, | 796 | void *start, unsigned long len, |
785 | unsigned char *end) | 797 | unsigned char *end, struct module *mod) |
786 | { | 798 | { |
787 | struct dwarf_fde *fde; | 799 | struct dwarf_fde *fde; |
788 | struct dwarf_cie *cie; | 800 | struct dwarf_cie *cie; |
@@ -831,6 +843,8 @@ static int dwarf_parse_fde(void *entry, u32 entry_type, | |||
831 | fde->instructions = p; | 843 | fde->instructions = p; |
832 | fde->end = end; | 844 | fde->end = end; |
833 | 845 | ||
846 | fde->mod = mod; | ||
847 | |||
834 | /* Add to list. */ | 848 | /* Add to list. */ |
835 | spin_lock_irqsave(&dwarf_fde_lock, flags); | 849 | spin_lock_irqsave(&dwarf_fde_lock, flags); |
836 | list_add_tail(&fde->link, &dwarf_fde_list); | 850 | list_add_tail(&fde->link, &dwarf_fde_list); |
@@ -854,10 +868,8 @@ static void dwarf_unwinder_dump(struct task_struct *task, | |||
854 | while (1) { | 868 | while (1) { |
855 | frame = dwarf_unwind_stack(return_addr, _frame); | 869 | frame = dwarf_unwind_stack(return_addr, _frame); |
856 | 870 | ||
857 | if (_frame) { | 871 | if (_frame) |
858 | dwarf_frame_free_regs(_frame); | 872 | dwarf_free_frame(_frame); |
859 | mempool_free(_frame, dwarf_frame_pool); | ||
860 | } | ||
861 | 873 | ||
862 | _frame = frame; | 874 | _frame = frame; |
863 | 875 | ||
@@ -867,6 +879,9 @@ static void dwarf_unwinder_dump(struct task_struct *task, | |||
867 | return_addr = frame->return_addr; | 879 | return_addr = frame->return_addr; |
868 | ops->address(data, return_addr, 1); | 880 | ops->address(data, return_addr, 1); |
869 | } | 881 | } |
882 | |||
883 | if (frame) | ||
884 | dwarf_free_frame(frame); | ||
870 | } | 885 | } |
871 | 886 | ||
872 | static struct unwinder dwarf_unwinder = { | 887 | static struct unwinder dwarf_unwinder = { |
@@ -896,48 +911,28 @@ static void dwarf_unwinder_cleanup(void) | |||
896 | } | 911 | } |
897 | 912 | ||
898 | /** | 913 | /** |
899 | * dwarf_unwinder_init - initialise the dwarf unwinder | 914 | * dwarf_parse_section - parse DWARF section |
915 | * @eh_frame_start: start address of the .eh_frame section | ||
916 | * @eh_frame_end: end address of the .eh_frame section | ||
917 | * @mod: the kernel module containing the .eh_frame section | ||
900 | * | 918 | * |
901 | * Build the data structures describing the .dwarf_frame section to | 919 | * Parse the information in a .eh_frame section. |
902 | * make it easier to lookup CIE and FDE entries. Because the | ||
903 | * .eh_frame section is packed as tightly as possible it is not | ||
904 | * easy to lookup the FDE for a given PC, so we build a list of FDE | ||
905 | * and CIE entries that make it easier. | ||
906 | */ | 920 | */ |
907 | static int __init dwarf_unwinder_init(void) | 921 | static int dwarf_parse_section(char *eh_frame_start, char *eh_frame_end, |
922 | struct module *mod) | ||
908 | { | 923 | { |
909 | u32 entry_type; | 924 | u32 entry_type; |
910 | void *p, *entry; | 925 | void *p, *entry; |
911 | int count, err = 0; | 926 | int count, err = 0; |
912 | unsigned long len; | 927 | unsigned long len = 0; |
913 | unsigned int c_entries, f_entries; | 928 | unsigned int c_entries, f_entries; |
914 | unsigned char *end; | 929 | unsigned char *end; |
915 | INIT_LIST_HEAD(&dwarf_cie_list); | ||
916 | INIT_LIST_HEAD(&dwarf_fde_list); | ||
917 | 930 | ||
918 | c_entries = 0; | 931 | c_entries = 0; |
919 | f_entries = 0; | 932 | f_entries = 0; |
920 | entry = &__start_eh_frame; | 933 | entry = eh_frame_start; |
921 | |||
922 | dwarf_frame_cachep = kmem_cache_create("dwarf_frames", | ||
923 | sizeof(struct dwarf_frame), 0, | ||
924 | SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL); | ||
925 | |||
926 | dwarf_reg_cachep = kmem_cache_create("dwarf_regs", | ||
927 | sizeof(struct dwarf_reg), 0, | ||
928 | SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL); | ||
929 | 934 | ||
930 | dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ, | 935 | while ((char *)entry < eh_frame_end) { |
931 | mempool_alloc_slab, | ||
932 | mempool_free_slab, | ||
933 | dwarf_frame_cachep); | ||
934 | |||
935 | dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ, | ||
936 | mempool_alloc_slab, | ||
937 | mempool_free_slab, | ||
938 | dwarf_reg_cachep); | ||
939 | |||
940 | while ((char *)entry < __stop_eh_frame) { | ||
941 | p = entry; | 936 | p = entry; |
942 | 937 | ||
943 | count = dwarf_entry_len(p, &len); | 938 | count = dwarf_entry_len(p, &len); |
@@ -949,6 +944,7 @@ static int __init dwarf_unwinder_init(void) | |||
949 | * entry and move to the next one because 'len' | 944 | * entry and move to the next one because 'len' |
950 | * tells us where our next entry is. | 945 | * tells us where our next entry is. |
951 | */ | 946 | */ |
947 | err = -EINVAL; | ||
952 | goto out; | 948 | goto out; |
953 | } else | 949 | } else |
954 | p += count; | 950 | p += count; |
@@ -960,13 +956,14 @@ static int __init dwarf_unwinder_init(void) | |||
960 | p += 4; | 956 | p += 4; |
961 | 957 | ||
962 | if (entry_type == DW_EH_FRAME_CIE) { | 958 | if (entry_type == DW_EH_FRAME_CIE) { |
963 | err = dwarf_parse_cie(entry, p, len, end); | 959 | err = dwarf_parse_cie(entry, p, len, end, mod); |
964 | if (err < 0) | 960 | if (err < 0) |
965 | goto out; | 961 | goto out; |
966 | else | 962 | else |
967 | c_entries++; | 963 | c_entries++; |
968 | } else { | 964 | } else { |
969 | err = dwarf_parse_fde(entry, entry_type, p, len, end); | 965 | err = dwarf_parse_fde(entry, entry_type, p, len, |
966 | end, mod); | ||
970 | if (err < 0) | 967 | if (err < 0) |
971 | goto out; | 968 | goto out; |
972 | else | 969 | else |
@@ -979,6 +976,129 @@ static int __init dwarf_unwinder_init(void) | |||
979 | printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n", | 976 | printk(KERN_INFO "DWARF unwinder initialised: read %u CIEs, %u FDEs\n", |
980 | c_entries, f_entries); | 977 | c_entries, f_entries); |
981 | 978 | ||
979 | return 0; | ||
980 | |||
981 | out: | ||
982 | return err; | ||
983 | } | ||
984 | |||
985 | #ifdef CONFIG_MODULES | ||
986 | int module_dwarf_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs, | ||
987 | struct module *me) | ||
988 | { | ||
989 | unsigned int i, err; | ||
990 | unsigned long start, end; | ||
991 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
992 | |||
993 | start = end = 0; | ||
994 | |||
995 | for (i = 1; i < hdr->e_shnum; i++) { | ||
996 | /* Alloc bit cleared means "ignore it." */ | ||
997 | if ((sechdrs[i].sh_flags & SHF_ALLOC) | ||
998 | && !strcmp(secstrings+sechdrs[i].sh_name, ".eh_frame")) { | ||
999 | start = sechdrs[i].sh_addr; | ||
1000 | end = start + sechdrs[i].sh_size; | ||
1001 | break; | ||
1002 | } | ||
1003 | } | ||
1004 | |||
1005 | /* Did we find the .eh_frame section? */ | ||
1006 | if (i != hdr->e_shnum) { | ||
1007 | err = dwarf_parse_section((char *)start, (char *)end, me); | ||
1008 | if (err) { | ||
1009 | printk(KERN_WARNING "%s: failed to parse DWARF info\n", | ||
1010 | me->name); | ||
1011 | return err; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | /** | ||
1019 | * module_dwarf_cleanup - remove FDE/CIEs associated with @mod | ||
1020 | * @mod: the module that is being unloaded | ||
1021 | * | ||
1022 | * Remove any FDEs and CIEs from the global lists that came from | ||
1023 | * @mod's .eh_frame section because @mod is being unloaded. | ||
1024 | */ | ||
1025 | void module_dwarf_cleanup(struct module *mod) | ||
1026 | { | ||
1027 | struct dwarf_fde *fde; | ||
1028 | struct dwarf_cie *cie; | ||
1029 | unsigned long flags; | ||
1030 | |||
1031 | spin_lock_irqsave(&dwarf_cie_lock, flags); | ||
1032 | |||
1033 | again_cie: | ||
1034 | list_for_each_entry(cie, &dwarf_cie_list, link) { | ||
1035 | if (cie->mod == mod) | ||
1036 | break; | ||
1037 | } | ||
1038 | |||
1039 | if (&cie->link != &dwarf_cie_list) { | ||
1040 | list_del(&cie->link); | ||
1041 | kfree(cie); | ||
1042 | goto again_cie; | ||
1043 | } | ||
1044 | |||
1045 | spin_unlock_irqrestore(&dwarf_cie_lock, flags); | ||
1046 | |||
1047 | spin_lock_irqsave(&dwarf_fde_lock, flags); | ||
1048 | |||
1049 | again_fde: | ||
1050 | list_for_each_entry(fde, &dwarf_fde_list, link) { | ||
1051 | if (fde->mod == mod) | ||
1052 | break; | ||
1053 | } | ||
1054 | |||
1055 | if (&fde->link != &dwarf_fde_list) { | ||
1056 | list_del(&fde->link); | ||
1057 | kfree(fde); | ||
1058 | goto again_fde; | ||
1059 | } | ||
1060 | |||
1061 | spin_unlock_irqrestore(&dwarf_fde_lock, flags); | ||
1062 | } | ||
1063 | #endif /* CONFIG_MODULES */ | ||
1064 | |||
1065 | /** | ||
1066 | * dwarf_unwinder_init - initialise the dwarf unwinder | ||
1067 | * | ||
1068 | * Build the data structures describing the .dwarf_frame section to | ||
1069 | * make it easier to lookup CIE and FDE entries. Because the | ||
1070 | * .eh_frame section is packed as tightly as possible it is not | ||
1071 | * easy to lookup the FDE for a given PC, so we build a list of FDE | ||
1072 | * and CIE entries that make it easier. | ||
1073 | */ | ||
1074 | static int __init dwarf_unwinder_init(void) | ||
1075 | { | ||
1076 | int err; | ||
1077 | INIT_LIST_HEAD(&dwarf_cie_list); | ||
1078 | INIT_LIST_HEAD(&dwarf_fde_list); | ||
1079 | |||
1080 | dwarf_frame_cachep = kmem_cache_create("dwarf_frames", | ||
1081 | sizeof(struct dwarf_frame), 0, | ||
1082 | SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL); | ||
1083 | |||
1084 | dwarf_reg_cachep = kmem_cache_create("dwarf_regs", | ||
1085 | sizeof(struct dwarf_reg), 0, | ||
1086 | SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL); | ||
1087 | |||
1088 | dwarf_frame_pool = mempool_create(DWARF_FRAME_MIN_REQ, | ||
1089 | mempool_alloc_slab, | ||
1090 | mempool_free_slab, | ||
1091 | dwarf_frame_cachep); | ||
1092 | |||
1093 | dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ, | ||
1094 | mempool_alloc_slab, | ||
1095 | mempool_free_slab, | ||
1096 | dwarf_reg_cachep); | ||
1097 | |||
1098 | err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL); | ||
1099 | if (err) | ||
1100 | goto out; | ||
1101 | |||
982 | err = unwinder_register(&dwarf_unwinder); | 1102 | err = unwinder_register(&dwarf_unwinder); |
983 | if (err) | 1103 | if (err) |
984 | goto out; | 1104 | goto out; |
diff --git a/arch/sh/kernel/entry-common.S b/arch/sh/kernel/entry-common.S index 3eb84931d2aa..f0abd58c3a69 100644 --- a/arch/sh/kernel/entry-common.S +++ b/arch/sh/kernel/entry-common.S | |||
@@ -133,7 +133,7 @@ work_pending: | |||
133 | ! r8: current_thread_info | 133 | ! r8: current_thread_info |
134 | ! t: result of "tst #_TIF_NEED_RESCHED, r0" | 134 | ! t: result of "tst #_TIF_NEED_RESCHED, r0" |
135 | bf/s work_resched | 135 | bf/s work_resched |
136 | tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0 | 136 | tst #_TIF_SIGPENDING, r0 |
137 | work_notifysig: | 137 | work_notifysig: |
138 | bt/s __restore_all | 138 | bt/s __restore_all |
139 | mov r15, r4 | 139 | mov r15, r4 |
diff --git a/arch/sh/kernel/ftrace.c b/arch/sh/kernel/ftrace.c index 2c48e267256e..b6f41c109beb 100644 --- a/arch/sh/kernel/ftrace.c +++ b/arch/sh/kernel/ftrace.c | |||
@@ -62,6 +62,150 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | |||
62 | return ftrace_replaced_code; | 62 | return ftrace_replaced_code; |
63 | } | 63 | } |
64 | 64 | ||
65 | /* | ||
66 | * Modifying code must take extra care. On an SMP machine, if | ||
67 | * the code being modified is also being executed on another CPU | ||
68 | * that CPU will have undefined results and possibly take a GPF. | ||
69 | * We use kstop_machine to stop other CPUS from exectuing code. | ||
70 | * But this does not stop NMIs from happening. We still need | ||
71 | * to protect against that. We separate out the modification of | ||
72 | * the code to take care of this. | ||
73 | * | ||
74 | * Two buffers are added: An IP buffer and a "code" buffer. | ||
75 | * | ||
76 | * 1) Put the instruction pointer into the IP buffer | ||
77 | * and the new code into the "code" buffer. | ||
78 | * 2) Wait for any running NMIs to finish and set a flag that says | ||
79 | * we are modifying code, it is done in an atomic operation. | ||
80 | * 3) Write the code | ||
81 | * 4) clear the flag. | ||
82 | * 5) Wait for any running NMIs to finish. | ||
83 | * | ||
84 | * If an NMI is executed, the first thing it does is to call | ||
85 | * "ftrace_nmi_enter". This will check if the flag is set to write | ||
86 | * and if it is, it will write what is in the IP and "code" buffers. | ||
87 | * | ||
88 | * The trick is, it does not matter if everyone is writing the same | ||
89 | * content to the code location. Also, if a CPU is executing code | ||
90 | * it is OK to write to that code location if the contents being written | ||
91 | * are the same as what exists. | ||
92 | */ | ||
93 | #define MOD_CODE_WRITE_FLAG (1 << 31) /* set when NMI should do the write */ | ||
94 | static atomic_t nmi_running = ATOMIC_INIT(0); | ||
95 | static int mod_code_status; /* holds return value of text write */ | ||
96 | static void *mod_code_ip; /* holds the IP to write to */ | ||
97 | static void *mod_code_newcode; /* holds the text to write to the IP */ | ||
98 | |||
99 | static unsigned nmi_wait_count; | ||
100 | static atomic_t nmi_update_count = ATOMIC_INIT(0); | ||
101 | |||
102 | int ftrace_arch_read_dyn_info(char *buf, int size) | ||
103 | { | ||
104 | int r; | ||
105 | |||
106 | r = snprintf(buf, size, "%u %u", | ||
107 | nmi_wait_count, | ||
108 | atomic_read(&nmi_update_count)); | ||
109 | return r; | ||
110 | } | ||
111 | |||
112 | static void clear_mod_flag(void) | ||
113 | { | ||
114 | int old = atomic_read(&nmi_running); | ||
115 | |||
116 | for (;;) { | ||
117 | int new = old & ~MOD_CODE_WRITE_FLAG; | ||
118 | |||
119 | if (old == new) | ||
120 | break; | ||
121 | |||
122 | old = atomic_cmpxchg(&nmi_running, old, new); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | static void ftrace_mod_code(void) | ||
127 | { | ||
128 | /* | ||
129 | * Yes, more than one CPU process can be writing to mod_code_status. | ||
130 | * (and the code itself) | ||
131 | * But if one were to fail, then they all should, and if one were | ||
132 | * to succeed, then they all should. | ||
133 | */ | ||
134 | mod_code_status = probe_kernel_write(mod_code_ip, mod_code_newcode, | ||
135 | MCOUNT_INSN_SIZE); | ||
136 | |||
137 | /* if we fail, then kill any new writers */ | ||
138 | if (mod_code_status) | ||
139 | clear_mod_flag(); | ||
140 | } | ||
141 | |||
142 | void ftrace_nmi_enter(void) | ||
143 | { | ||
144 | if (atomic_inc_return(&nmi_running) & MOD_CODE_WRITE_FLAG) { | ||
145 | smp_rmb(); | ||
146 | ftrace_mod_code(); | ||
147 | atomic_inc(&nmi_update_count); | ||
148 | } | ||
149 | /* Must have previous changes seen before executions */ | ||
150 | smp_mb(); | ||
151 | } | ||
152 | |||
153 | void ftrace_nmi_exit(void) | ||
154 | { | ||
155 | /* Finish all executions before clearing nmi_running */ | ||
156 | smp_mb(); | ||
157 | atomic_dec(&nmi_running); | ||
158 | } | ||
159 | |||
160 | static void wait_for_nmi_and_set_mod_flag(void) | ||
161 | { | ||
162 | if (!atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG)) | ||
163 | return; | ||
164 | |||
165 | do { | ||
166 | cpu_relax(); | ||
167 | } while (atomic_cmpxchg(&nmi_running, 0, MOD_CODE_WRITE_FLAG)); | ||
168 | |||
169 | nmi_wait_count++; | ||
170 | } | ||
171 | |||
172 | static void wait_for_nmi(void) | ||
173 | { | ||
174 | if (!atomic_read(&nmi_running)) | ||
175 | return; | ||
176 | |||
177 | do { | ||
178 | cpu_relax(); | ||
179 | } while (atomic_read(&nmi_running)); | ||
180 | |||
181 | nmi_wait_count++; | ||
182 | } | ||
183 | |||
184 | static int | ||
185 | do_ftrace_mod_code(unsigned long ip, void *new_code) | ||
186 | { | ||
187 | mod_code_ip = (void *)ip; | ||
188 | mod_code_newcode = new_code; | ||
189 | |||
190 | /* The buffers need to be visible before we let NMIs write them */ | ||
191 | smp_mb(); | ||
192 | |||
193 | wait_for_nmi_and_set_mod_flag(); | ||
194 | |||
195 | /* Make sure all running NMIs have finished before we write the code */ | ||
196 | smp_mb(); | ||
197 | |||
198 | ftrace_mod_code(); | ||
199 | |||
200 | /* Make sure the write happens before clearing the bit */ | ||
201 | smp_mb(); | ||
202 | |||
203 | clear_mod_flag(); | ||
204 | wait_for_nmi(); | ||
205 | |||
206 | return mod_code_status; | ||
207 | } | ||
208 | |||
65 | static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, | 209 | static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, |
66 | unsigned char *new_code) | 210 | unsigned char *new_code) |
67 | { | 211 | { |
@@ -86,7 +230,7 @@ static int ftrace_modify_code(unsigned long ip, unsigned char *old_code, | |||
86 | return -EINVAL; | 230 | return -EINVAL; |
87 | 231 | ||
88 | /* replace the text with the new text */ | 232 | /* replace the text with the new text */ |
89 | if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) | 233 | if (do_ftrace_mod_code(ip, new_code)) |
90 | return -EPERM; | 234 | return -EPERM; |
91 | 235 | ||
92 | flush_icache_range(ip, ip + MCOUNT_INSN_SIZE); | 236 | flush_icache_range(ip, ip + MCOUNT_INSN_SIZE); |
diff --git a/arch/sh/kernel/gpio.c b/arch/sh/kernel/gpio.c deleted file mode 100644 index d22e5af699f9..000000000000 --- a/arch/sh/kernel/gpio.c +++ /dev/null | |||
@@ -1,584 +0,0 @@ | |||
1 | /* | ||
2 | * Pinmuxed GPIO support for SuperH. | ||
3 | * | ||
4 | * Copyright (C) 2008 Magnus Damm | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | |||
11 | #include <linux/errno.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/list.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/clk.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/bitops.h> | ||
20 | #include <linux/gpio.h> | ||
21 | |||
22 | static int enum_in_range(pinmux_enum_t enum_id, struct pinmux_range *r) | ||
23 | { | ||
24 | if (enum_id < r->begin) | ||
25 | return 0; | ||
26 | |||
27 | if (enum_id > r->end) | ||
28 | return 0; | ||
29 | |||
30 | return 1; | ||
31 | } | ||
32 | |||
33 | static unsigned long gpio_read_raw_reg(unsigned long reg, | ||
34 | unsigned long reg_width) | ||
35 | { | ||
36 | switch (reg_width) { | ||
37 | case 8: | ||
38 | return ctrl_inb(reg); | ||
39 | case 16: | ||
40 | return ctrl_inw(reg); | ||
41 | case 32: | ||
42 | return ctrl_inl(reg); | ||
43 | } | ||
44 | |||
45 | BUG(); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static void gpio_write_raw_reg(unsigned long reg, | ||
50 | unsigned long reg_width, | ||
51 | unsigned long data) | ||
52 | { | ||
53 | switch (reg_width) { | ||
54 | case 8: | ||
55 | ctrl_outb(data, reg); | ||
56 | return; | ||
57 | case 16: | ||
58 | ctrl_outw(data, reg); | ||
59 | return; | ||
60 | case 32: | ||
61 | ctrl_outl(data, reg); | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | BUG(); | ||
66 | } | ||
67 | |||
68 | static void gpio_write_bit(struct pinmux_data_reg *dr, | ||
69 | unsigned long in_pos, unsigned long value) | ||
70 | { | ||
71 | unsigned long pos; | ||
72 | |||
73 | pos = dr->reg_width - (in_pos + 1); | ||
74 | |||
75 | #ifdef DEBUG | ||
76 | pr_info("write_bit addr = %lx, value = %ld, pos = %ld, " | ||
77 | "r_width = %ld\n", | ||
78 | dr->reg, !!value, pos, dr->reg_width); | ||
79 | #endif | ||
80 | |||
81 | if (value) | ||
82 | set_bit(pos, &dr->reg_shadow); | ||
83 | else | ||
84 | clear_bit(pos, &dr->reg_shadow); | ||
85 | |||
86 | gpio_write_raw_reg(dr->reg, dr->reg_width, dr->reg_shadow); | ||
87 | } | ||
88 | |||
89 | static int gpio_read_reg(unsigned long reg, unsigned long reg_width, | ||
90 | unsigned long field_width, unsigned long in_pos) | ||
91 | { | ||
92 | unsigned long data, mask, pos; | ||
93 | |||
94 | data = 0; | ||
95 | mask = (1 << field_width) - 1; | ||
96 | pos = reg_width - ((in_pos + 1) * field_width); | ||
97 | |||
98 | #ifdef DEBUG | ||
99 | pr_info("read_reg: addr = %lx, pos = %ld, " | ||
100 | "r_width = %ld, f_width = %ld\n", | ||
101 | reg, pos, reg_width, field_width); | ||
102 | #endif | ||
103 | |||
104 | data = gpio_read_raw_reg(reg, reg_width); | ||
105 | return (data >> pos) & mask; | ||
106 | } | ||
107 | |||
108 | static void gpio_write_reg(unsigned long reg, unsigned long reg_width, | ||
109 | unsigned long field_width, unsigned long in_pos, | ||
110 | unsigned long value) | ||
111 | { | ||
112 | unsigned long mask, pos; | ||
113 | |||
114 | mask = (1 << field_width) - 1; | ||
115 | pos = reg_width - ((in_pos + 1) * field_width); | ||
116 | |||
117 | #ifdef DEBUG | ||
118 | pr_info("write_reg addr = %lx, value = %ld, pos = %ld, " | ||
119 | "r_width = %ld, f_width = %ld\n", | ||
120 | reg, value, pos, reg_width, field_width); | ||
121 | #endif | ||
122 | |||
123 | mask = ~(mask << pos); | ||
124 | value = value << pos; | ||
125 | |||
126 | switch (reg_width) { | ||
127 | case 8: | ||
128 | ctrl_outb((ctrl_inb(reg) & mask) | value, reg); | ||
129 | break; | ||
130 | case 16: | ||
131 | ctrl_outw((ctrl_inw(reg) & mask) | value, reg); | ||
132 | break; | ||
133 | case 32: | ||
134 | ctrl_outl((ctrl_inl(reg) & mask) | value, reg); | ||
135 | break; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | static int setup_data_reg(struct pinmux_info *gpioc, unsigned gpio) | ||
140 | { | ||
141 | struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | ||
142 | struct pinmux_data_reg *data_reg; | ||
143 | int k, n; | ||
144 | |||
145 | if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | ||
146 | return -1; | ||
147 | |||
148 | k = 0; | ||
149 | while (1) { | ||
150 | data_reg = gpioc->data_regs + k; | ||
151 | |||
152 | if (!data_reg->reg_width) | ||
153 | break; | ||
154 | |||
155 | for (n = 0; n < data_reg->reg_width; n++) { | ||
156 | if (data_reg->enum_ids[n] == gpiop->enum_id) { | ||
157 | gpiop->flags &= ~PINMUX_FLAG_DREG; | ||
158 | gpiop->flags |= (k << PINMUX_FLAG_DREG_SHIFT); | ||
159 | gpiop->flags &= ~PINMUX_FLAG_DBIT; | ||
160 | gpiop->flags |= (n << PINMUX_FLAG_DBIT_SHIFT); | ||
161 | return 0; | ||
162 | } | ||
163 | } | ||
164 | k++; | ||
165 | } | ||
166 | |||
167 | BUG(); | ||
168 | |||
169 | return -1; | ||
170 | } | ||
171 | |||
172 | static void setup_data_regs(struct pinmux_info *gpioc) | ||
173 | { | ||
174 | struct pinmux_data_reg *drp; | ||
175 | int k; | ||
176 | |||
177 | for (k = gpioc->first_gpio; k <= gpioc->last_gpio; k++) | ||
178 | setup_data_reg(gpioc, k); | ||
179 | |||
180 | k = 0; | ||
181 | while (1) { | ||
182 | drp = gpioc->data_regs + k; | ||
183 | |||
184 | if (!drp->reg_width) | ||
185 | break; | ||
186 | |||
187 | drp->reg_shadow = gpio_read_raw_reg(drp->reg, drp->reg_width); | ||
188 | k++; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static int get_data_reg(struct pinmux_info *gpioc, unsigned gpio, | ||
193 | struct pinmux_data_reg **drp, int *bitp) | ||
194 | { | ||
195 | struct pinmux_gpio *gpiop = &gpioc->gpios[gpio]; | ||
196 | int k, n; | ||
197 | |||
198 | if (!enum_in_range(gpiop->enum_id, &gpioc->data)) | ||
199 | return -1; | ||
200 | |||
201 | k = (gpiop->flags & PINMUX_FLAG_DREG) >> PINMUX_FLAG_DREG_SHIFT; | ||
202 | n = (gpiop->flags & PINMUX_FLAG_DBIT) >> PINMUX_FLAG_DBIT_SHIFT; | ||
203 | *drp = gpioc->data_regs + k; | ||
204 | *bitp = n; | ||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static int get_config_reg(struct pinmux_info *gpioc, pinmux_enum_t enum_id, | ||
209 | struct pinmux_cfg_reg **crp, int *indexp, | ||
210 | unsigned long **cntp) | ||
211 | { | ||
212 | struct pinmux_cfg_reg *config_reg; | ||
213 | unsigned long r_width, f_width; | ||
214 | int k, n; | ||
215 | |||
216 | k = 0; | ||
217 | while (1) { | ||
218 | config_reg = gpioc->cfg_regs + k; | ||
219 | |||
220 | r_width = config_reg->reg_width; | ||
221 | f_width = config_reg->field_width; | ||
222 | |||
223 | if (!r_width) | ||
224 | break; | ||
225 | for (n = 0; n < (r_width / f_width) * 1 << f_width; n++) { | ||
226 | if (config_reg->enum_ids[n] == enum_id) { | ||
227 | *crp = config_reg; | ||
228 | *indexp = n; | ||
229 | *cntp = &config_reg->cnt[n / (1 << f_width)]; | ||
230 | return 0; | ||
231 | } | ||
232 | } | ||
233 | k++; | ||
234 | } | ||
235 | |||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | static int get_gpio_enum_id(struct pinmux_info *gpioc, unsigned gpio, | ||
240 | int pos, pinmux_enum_t *enum_idp) | ||
241 | { | ||
242 | pinmux_enum_t enum_id = gpioc->gpios[gpio].enum_id; | ||
243 | pinmux_enum_t *data = gpioc->gpio_data; | ||
244 | int k; | ||
245 | |||
246 | if (!enum_in_range(enum_id, &gpioc->data)) { | ||
247 | if (!enum_in_range(enum_id, &gpioc->mark)) { | ||
248 | pr_err("non data/mark enum_id for gpio %d\n", gpio); | ||
249 | return -1; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | if (pos) { | ||
254 | *enum_idp = data[pos + 1]; | ||
255 | return pos + 1; | ||
256 | } | ||
257 | |||
258 | for (k = 0; k < gpioc->gpio_data_size; k++) { | ||
259 | if (data[k] == enum_id) { | ||
260 | *enum_idp = data[k + 1]; | ||
261 | return k + 1; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | pr_err("cannot locate data/mark enum_id for gpio %d\n", gpio); | ||
266 | return -1; | ||
267 | } | ||
268 | |||
269 | static void write_config_reg(struct pinmux_info *gpioc, | ||
270 | struct pinmux_cfg_reg *crp, | ||
271 | int index) | ||
272 | { | ||
273 | unsigned long ncomb, pos, value; | ||
274 | |||
275 | ncomb = 1 << crp->field_width; | ||
276 | pos = index / ncomb; | ||
277 | value = index % ncomb; | ||
278 | |||
279 | gpio_write_reg(crp->reg, crp->reg_width, crp->field_width, pos, value); | ||
280 | } | ||
281 | |||
282 | static int check_config_reg(struct pinmux_info *gpioc, | ||
283 | struct pinmux_cfg_reg *crp, | ||
284 | int index) | ||
285 | { | ||
286 | unsigned long ncomb, pos, value; | ||
287 | |||
288 | ncomb = 1 << crp->field_width; | ||
289 | pos = index / ncomb; | ||
290 | value = index % ncomb; | ||
291 | |||
292 | if (gpio_read_reg(crp->reg, crp->reg_width, | ||
293 | crp->field_width, pos) == value) | ||
294 | return 0; | ||
295 | |||
296 | return -1; | ||
297 | } | ||
298 | |||
299 | enum { GPIO_CFG_DRYRUN, GPIO_CFG_REQ, GPIO_CFG_FREE }; | ||
300 | |||
301 | static int pinmux_config_gpio(struct pinmux_info *gpioc, unsigned gpio, | ||
302 | int pinmux_type, int cfg_mode) | ||
303 | { | ||
304 | struct pinmux_cfg_reg *cr = NULL; | ||
305 | pinmux_enum_t enum_id; | ||
306 | struct pinmux_range *range; | ||
307 | int in_range, pos, index; | ||
308 | unsigned long *cntp; | ||
309 | |||
310 | switch (pinmux_type) { | ||
311 | |||
312 | case PINMUX_TYPE_FUNCTION: | ||
313 | range = NULL; | ||
314 | break; | ||
315 | |||
316 | case PINMUX_TYPE_OUTPUT: | ||
317 | range = &gpioc->output; | ||
318 | break; | ||
319 | |||
320 | case PINMUX_TYPE_INPUT: | ||
321 | range = &gpioc->input; | ||
322 | break; | ||
323 | |||
324 | case PINMUX_TYPE_INPUT_PULLUP: | ||
325 | range = &gpioc->input_pu; | ||
326 | break; | ||
327 | |||
328 | case PINMUX_TYPE_INPUT_PULLDOWN: | ||
329 | range = &gpioc->input_pd; | ||
330 | break; | ||
331 | |||
332 | default: | ||
333 | goto out_err; | ||
334 | } | ||
335 | |||
336 | pos = 0; | ||
337 | enum_id = 0; | ||
338 | index = 0; | ||
339 | while (1) { | ||
340 | pos = get_gpio_enum_id(gpioc, gpio, pos, &enum_id); | ||
341 | if (pos <= 0) | ||
342 | goto out_err; | ||
343 | |||
344 | if (!enum_id) | ||
345 | break; | ||
346 | |||
347 | in_range = enum_in_range(enum_id, &gpioc->function); | ||
348 | if (!in_range && range) { | ||
349 | in_range = enum_in_range(enum_id, range); | ||
350 | |||
351 | if (in_range && enum_id == range->force) | ||
352 | continue; | ||
353 | } | ||
354 | |||
355 | if (!in_range) | ||
356 | continue; | ||
357 | |||
358 | if (get_config_reg(gpioc, enum_id, &cr, &index, &cntp) != 0) | ||
359 | goto out_err; | ||
360 | |||
361 | switch (cfg_mode) { | ||
362 | case GPIO_CFG_DRYRUN: | ||
363 | if (!*cntp || !check_config_reg(gpioc, cr, index)) | ||
364 | continue; | ||
365 | break; | ||
366 | |||
367 | case GPIO_CFG_REQ: | ||
368 | write_config_reg(gpioc, cr, index); | ||
369 | *cntp = *cntp + 1; | ||
370 | break; | ||
371 | |||
372 | case GPIO_CFG_FREE: | ||
373 | *cntp = *cntp - 1; | ||
374 | break; | ||
375 | } | ||
376 | } | ||
377 | |||
378 | return 0; | ||
379 | out_err: | ||
380 | return -1; | ||
381 | } | ||
382 | |||
383 | static DEFINE_SPINLOCK(gpio_lock); | ||
384 | |||
385 | static struct pinmux_info *chip_to_pinmux(struct gpio_chip *chip) | ||
386 | { | ||
387 | return container_of(chip, struct pinmux_info, chip); | ||
388 | } | ||
389 | |||
390 | static int sh_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
391 | { | ||
392 | struct pinmux_info *gpioc = chip_to_pinmux(chip); | ||
393 | struct pinmux_data_reg *dummy; | ||
394 | unsigned long flags; | ||
395 | int i, ret, pinmux_type; | ||
396 | |||
397 | ret = -EINVAL; | ||
398 | |||
399 | if (!gpioc) | ||
400 | goto err_out; | ||
401 | |||
402 | spin_lock_irqsave(&gpio_lock, flags); | ||
403 | |||
404 | if ((gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE) != PINMUX_TYPE_NONE) | ||
405 | goto err_unlock; | ||
406 | |||
407 | /* setup pin function here if no data is associated with pin */ | ||
408 | |||
409 | if (get_data_reg(gpioc, offset, &dummy, &i) != 0) | ||
410 | pinmux_type = PINMUX_TYPE_FUNCTION; | ||
411 | else | ||
412 | pinmux_type = PINMUX_TYPE_GPIO; | ||
413 | |||
414 | if (pinmux_type == PINMUX_TYPE_FUNCTION) { | ||
415 | if (pinmux_config_gpio(gpioc, offset, | ||
416 | pinmux_type, | ||
417 | GPIO_CFG_DRYRUN) != 0) | ||
418 | goto err_unlock; | ||
419 | |||
420 | if (pinmux_config_gpio(gpioc, offset, | ||
421 | pinmux_type, | ||
422 | GPIO_CFG_REQ) != 0) | ||
423 | BUG(); | ||
424 | } | ||
425 | |||
426 | gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | ||
427 | gpioc->gpios[offset].flags |= pinmux_type; | ||
428 | |||
429 | ret = 0; | ||
430 | err_unlock: | ||
431 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
432 | err_out: | ||
433 | return ret; | ||
434 | } | ||
435 | |||
436 | static void sh_gpio_free(struct gpio_chip *chip, unsigned offset) | ||
437 | { | ||
438 | struct pinmux_info *gpioc = chip_to_pinmux(chip); | ||
439 | unsigned long flags; | ||
440 | int pinmux_type; | ||
441 | |||
442 | if (!gpioc) | ||
443 | return; | ||
444 | |||
445 | spin_lock_irqsave(&gpio_lock, flags); | ||
446 | |||
447 | pinmux_type = gpioc->gpios[offset].flags & PINMUX_FLAG_TYPE; | ||
448 | pinmux_config_gpio(gpioc, offset, pinmux_type, GPIO_CFG_FREE); | ||
449 | gpioc->gpios[offset].flags &= ~PINMUX_FLAG_TYPE; | ||
450 | gpioc->gpios[offset].flags |= PINMUX_TYPE_NONE; | ||
451 | |||
452 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
453 | } | ||
454 | |||
455 | static int pinmux_direction(struct pinmux_info *gpioc, | ||
456 | unsigned gpio, int new_pinmux_type) | ||
457 | { | ||
458 | int pinmux_type; | ||
459 | int ret = -EINVAL; | ||
460 | |||
461 | if (!gpioc) | ||
462 | goto err_out; | ||
463 | |||
464 | pinmux_type = gpioc->gpios[gpio].flags & PINMUX_FLAG_TYPE; | ||
465 | |||
466 | switch (pinmux_type) { | ||
467 | case PINMUX_TYPE_GPIO: | ||
468 | break; | ||
469 | case PINMUX_TYPE_OUTPUT: | ||
470 | case PINMUX_TYPE_INPUT: | ||
471 | case PINMUX_TYPE_INPUT_PULLUP: | ||
472 | case PINMUX_TYPE_INPUT_PULLDOWN: | ||
473 | pinmux_config_gpio(gpioc, gpio, pinmux_type, GPIO_CFG_FREE); | ||
474 | break; | ||
475 | default: | ||
476 | goto err_out; | ||
477 | } | ||
478 | |||
479 | if (pinmux_config_gpio(gpioc, gpio, | ||
480 | new_pinmux_type, | ||
481 | GPIO_CFG_DRYRUN) != 0) | ||
482 | goto err_out; | ||
483 | |||
484 | if (pinmux_config_gpio(gpioc, gpio, | ||
485 | new_pinmux_type, | ||
486 | GPIO_CFG_REQ) != 0) | ||
487 | BUG(); | ||
488 | |||
489 | gpioc->gpios[gpio].flags &= ~PINMUX_FLAG_TYPE; | ||
490 | gpioc->gpios[gpio].flags |= new_pinmux_type; | ||
491 | |||
492 | ret = 0; | ||
493 | err_out: | ||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | static int sh_gpio_direction_input(struct gpio_chip *chip, unsigned offset) | ||
498 | { | ||
499 | struct pinmux_info *gpioc = chip_to_pinmux(chip); | ||
500 | unsigned long flags; | ||
501 | int ret; | ||
502 | |||
503 | spin_lock_irqsave(&gpio_lock, flags); | ||
504 | ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_INPUT); | ||
505 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
506 | |||
507 | return ret; | ||
508 | } | ||
509 | |||
510 | static void sh_gpio_set_value(struct pinmux_info *gpioc, | ||
511 | unsigned gpio, int value) | ||
512 | { | ||
513 | struct pinmux_data_reg *dr = NULL; | ||
514 | int bit = 0; | ||
515 | |||
516 | if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) | ||
517 | BUG(); | ||
518 | else | ||
519 | gpio_write_bit(dr, bit, value); | ||
520 | } | ||
521 | |||
522 | static int sh_gpio_direction_output(struct gpio_chip *chip, unsigned offset, | ||
523 | int value) | ||
524 | { | ||
525 | struct pinmux_info *gpioc = chip_to_pinmux(chip); | ||
526 | unsigned long flags; | ||
527 | int ret; | ||
528 | |||
529 | sh_gpio_set_value(gpioc, offset, value); | ||
530 | spin_lock_irqsave(&gpio_lock, flags); | ||
531 | ret = pinmux_direction(gpioc, offset, PINMUX_TYPE_OUTPUT); | ||
532 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
533 | |||
534 | return ret; | ||
535 | } | ||
536 | |||
537 | static int sh_gpio_get_value(struct pinmux_info *gpioc, unsigned gpio) | ||
538 | { | ||
539 | struct pinmux_data_reg *dr = NULL; | ||
540 | int bit = 0; | ||
541 | |||
542 | if (!gpioc || get_data_reg(gpioc, gpio, &dr, &bit) != 0) { | ||
543 | BUG(); | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | return gpio_read_reg(dr->reg, dr->reg_width, 1, bit); | ||
548 | } | ||
549 | |||
550 | static int sh_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
551 | { | ||
552 | return sh_gpio_get_value(chip_to_pinmux(chip), offset); | ||
553 | } | ||
554 | |||
555 | static void sh_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
556 | { | ||
557 | sh_gpio_set_value(chip_to_pinmux(chip), offset, value); | ||
558 | } | ||
559 | |||
560 | int register_pinmux(struct pinmux_info *pip) | ||
561 | { | ||
562 | struct gpio_chip *chip = &pip->chip; | ||
563 | |||
564 | pr_info("sh pinmux: %s handling gpio %d -> %d\n", | ||
565 | pip->name, pip->first_gpio, pip->last_gpio); | ||
566 | |||
567 | setup_data_regs(pip); | ||
568 | |||
569 | chip->request = sh_gpio_request; | ||
570 | chip->free = sh_gpio_free; | ||
571 | chip->direction_input = sh_gpio_direction_input; | ||
572 | chip->get = sh_gpio_get; | ||
573 | chip->direction_output = sh_gpio_direction_output; | ||
574 | chip->set = sh_gpio_set; | ||
575 | |||
576 | WARN_ON(pip->first_gpio != 0); /* needs testing */ | ||
577 | |||
578 | chip->label = pip->name; | ||
579 | chip->owner = THIS_MODULE; | ||
580 | chip->base = pip->first_gpio; | ||
581 | chip->ngpio = (pip->last_gpio - pip->first_gpio) + 1; | ||
582 | |||
583 | return gpiochip_add(chip); | ||
584 | } | ||
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index a78be74b8d3e..1151ecdffa71 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S | |||
@@ -33,7 +33,7 @@ ENTRY(empty_zero_page) | |||
33 | .long 1 /* LOADER_TYPE */ | 33 | .long 1 /* LOADER_TYPE */ |
34 | .long 0x00000000 /* INITRD_START */ | 34 | .long 0x00000000 /* INITRD_START */ |
35 | .long 0x00000000 /* INITRD_SIZE */ | 35 | .long 0x00000000 /* INITRD_SIZE */ |
36 | #ifdef CONFIG_32BIT | 36 | #if defined(CONFIG_32BIT) && defined(CONFIG_PMB_FIXED) |
37 | .long 0x53453f00 + 32 /* "SE?" = 32 bit */ | 37 | .long 0x53453f00 + 32 /* "SE?" = 32 bit */ |
38 | #else | 38 | #else |
39 | .long 0x53453f00 + 29 /* "SE?" = 29 bit */ | 39 | .long 0x53453f00 + 29 /* "SE?" = 29 bit */ |
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c index 27ff2dc093c7..aaff0037fcd7 100644 --- a/arch/sh/kernel/idle.c +++ b/arch/sh/kernel/idle.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include <asm/atomic.h> | 21 | #include <asm/atomic.h> |
22 | 22 | ||
23 | static int hlt_counter; | 23 | static int hlt_counter; |
24 | void (*pm_idle)(void); | 24 | void (*pm_idle)(void) = NULL; |
25 | void (*pm_power_off)(void); | 25 | void (*pm_power_off)(void); |
26 | EXPORT_SYMBOL(pm_power_off); | 26 | EXPORT_SYMBOL(pm_power_off); |
27 | 27 | ||
@@ -39,48 +39,92 @@ static int __init hlt_setup(char *__unused) | |||
39 | } | 39 | } |
40 | __setup("hlt", hlt_setup); | 40 | __setup("hlt", hlt_setup); |
41 | 41 | ||
42 | static inline int hlt_works(void) | ||
43 | { | ||
44 | return !hlt_counter; | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * On SMP it's slightly faster (but much more power-consuming!) | ||
49 | * to poll the ->work.need_resched flag instead of waiting for the | ||
50 | * cross-CPU IPI to arrive. Use this option with caution. | ||
51 | */ | ||
52 | static void poll_idle(void) | ||
53 | { | ||
54 | local_irq_enable(); | ||
55 | while (!need_resched()) | ||
56 | cpu_relax(); | ||
57 | } | ||
58 | |||
42 | void default_idle(void) | 59 | void default_idle(void) |
43 | { | 60 | { |
44 | if (!hlt_counter) { | 61 | if (hlt_works()) { |
45 | clear_thread_flag(TIF_POLLING_NRFLAG); | 62 | clear_thread_flag(TIF_POLLING_NRFLAG); |
46 | smp_mb__after_clear_bit(); | 63 | smp_mb__after_clear_bit(); |
47 | set_bl_bit(); | ||
48 | stop_critical_timings(); | ||
49 | 64 | ||
50 | while (!need_resched()) | 65 | if (!need_resched()) { |
66 | local_irq_enable(); | ||
51 | cpu_sleep(); | 67 | cpu_sleep(); |
68 | } else | ||
69 | local_irq_enable(); | ||
52 | 70 | ||
53 | start_critical_timings(); | ||
54 | clear_bl_bit(); | ||
55 | set_thread_flag(TIF_POLLING_NRFLAG); | 71 | set_thread_flag(TIF_POLLING_NRFLAG); |
56 | } else | 72 | } else |
57 | while (!need_resched()) | 73 | poll_idle(); |
58 | cpu_relax(); | ||
59 | } | 74 | } |
60 | 75 | ||
76 | /* | ||
77 | * The idle thread. There's no useful work to be done, so just try to conserve | ||
78 | * power and have a low exit latency (ie sit in a loop waiting for somebody to | ||
79 | * say that they'd like to reschedule) | ||
80 | */ | ||
61 | void cpu_idle(void) | 81 | void cpu_idle(void) |
62 | { | 82 | { |
83 | unsigned int cpu = smp_processor_id(); | ||
84 | |||
63 | set_thread_flag(TIF_POLLING_NRFLAG); | 85 | set_thread_flag(TIF_POLLING_NRFLAG); |
64 | 86 | ||
65 | /* endless idle loop with no priority at all */ | 87 | /* endless idle loop with no priority at all */ |
66 | while (1) { | 88 | while (1) { |
67 | void (*idle)(void) = pm_idle; | 89 | tick_nohz_stop_sched_tick(1); |
68 | 90 | ||
69 | if (!idle) | 91 | while (!need_resched() && cpu_online(cpu)) { |
70 | idle = default_idle; | 92 | check_pgt_cache(); |
93 | rmb(); | ||
71 | 94 | ||
72 | tick_nohz_stop_sched_tick(1); | 95 | local_irq_disable(); |
73 | while (!need_resched()) | 96 | /* Don't trace irqs off for idle */ |
74 | idle(); | 97 | stop_critical_timings(); |
75 | tick_nohz_restart_sched_tick(); | 98 | pm_idle(); |
99 | /* | ||
100 | * Sanity check to ensure that pm_idle() returns | ||
101 | * with IRQs enabled | ||
102 | */ | ||
103 | WARN_ON(irqs_disabled()); | ||
104 | start_critical_timings(); | ||
105 | } | ||
76 | 106 | ||
107 | tick_nohz_restart_sched_tick(); | ||
77 | preempt_enable_no_resched(); | 108 | preempt_enable_no_resched(); |
78 | schedule(); | 109 | schedule(); |
79 | preempt_disable(); | 110 | preempt_disable(); |
80 | check_pgt_cache(); | ||
81 | } | 111 | } |
82 | } | 112 | } |
83 | 113 | ||
114 | void __cpuinit select_idle_routine(void) | ||
115 | { | ||
116 | /* | ||
117 | * If a platform has set its own idle routine, leave it alone. | ||
118 | */ | ||
119 | if (pm_idle) | ||
120 | return; | ||
121 | |||
122 | if (hlt_works()) | ||
123 | pm_idle = default_idle; | ||
124 | else | ||
125 | pm_idle = poll_idle; | ||
126 | } | ||
127 | |||
84 | static void do_nothing(void *unused) | 128 | static void do_nothing(void *unused) |
85 | { | 129 | { |
86 | } | 130 | } |
diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c index b8fa6524760a..e1e1dbd19557 100644 --- a/arch/sh/kernel/io_generic.c +++ b/arch/sh/kernel/io_generic.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #define dummy_read() | 24 | #define dummy_read() |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | unsigned long generic_io_base; | 27 | unsigned long generic_io_base = 0; |
28 | 28 | ||
29 | u8 generic_inb(unsigned long port) | 29 | u8 generic_inb(unsigned long port) |
30 | { | 30 | { |
@@ -147,8 +147,10 @@ void generic_outsl(unsigned long port, const void *src, unsigned long count) | |||
147 | 147 | ||
148 | void __iomem *generic_ioport_map(unsigned long addr, unsigned int size) | 148 | void __iomem *generic_ioport_map(unsigned long addr, unsigned int size) |
149 | { | 149 | { |
150 | #ifdef P1SEG | ||
150 | if (PXSEG(addr) >= P1SEG) | 151 | if (PXSEG(addr) >= P1SEG) |
151 | return (void __iomem *)addr; | 152 | return (void __iomem *)addr; |
153 | #endif | ||
152 | 154 | ||
153 | return (void __iomem *)(addr + generic_io_base); | 155 | return (void __iomem *)(addr + generic_io_base); |
154 | } | 156 | } |
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index eac7da772fc2..e1913f28f418 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c | |||
@@ -37,7 +37,15 @@ void ack_bad_irq(unsigned int irq) | |||
37 | */ | 37 | */ |
38 | static int show_other_interrupts(struct seq_file *p, int prec) | 38 | static int show_other_interrupts(struct seq_file *p, int prec) |
39 | { | 39 | { |
40 | int j; | ||
41 | |||
42 | seq_printf(p, "%*s: ", prec, "NMI"); | ||
43 | for_each_online_cpu(j) | ||
44 | seq_printf(p, "%10u ", irq_stat[j].__nmi_count); | ||
45 | seq_printf(p, " Non-maskable interrupts\n"); | ||
46 | |||
40 | seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); | 47 | seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); |
48 | |||
41 | return 0; | 49 | return 0; |
42 | } | 50 | } |
43 | 51 | ||
@@ -255,6 +263,12 @@ void __init init_IRQ(void) | |||
255 | { | 263 | { |
256 | plat_irq_setup(); | 264 | plat_irq_setup(); |
257 | 265 | ||
266 | /* | ||
267 | * Pin any of the legacy IRQ vectors that haven't already been | ||
268 | * grabbed by the platform | ||
269 | */ | ||
270 | reserve_irq_legacy(); | ||
271 | |||
258 | /* Perform the machine specific initialisation */ | 272 | /* Perform the machine specific initialisation */ |
259 | if (sh_mv.mv_init_irq) | 273 | if (sh_mv.mv_init_irq) |
260 | sh_mv.mv_init_irq(); | 274 | sh_mv.mv_init_irq(); |
diff --git a/arch/sh/kernel/irq_32.c b/arch/sh/kernel/irq_32.c new file mode 100644 index 000000000000..e33ab15831f9 --- /dev/null +++ b/arch/sh/kernel/irq_32.c | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * SHcompact irqflags support | ||
3 | * | ||
4 | * Copyright (C) 2006 - 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/irqflags.h> | ||
11 | #include <linux/module.h> | ||
12 | |||
13 | void notrace raw_local_irq_restore(unsigned long flags) | ||
14 | { | ||
15 | unsigned long __dummy0, __dummy1; | ||
16 | |||
17 | if (flags == RAW_IRQ_DISABLED) { | ||
18 | __asm__ __volatile__ ( | ||
19 | "stc sr, %0\n\t" | ||
20 | "or #0xf0, %0\n\t" | ||
21 | "ldc %0, sr\n\t" | ||
22 | : "=&z" (__dummy0) | ||
23 | : /* no inputs */ | ||
24 | : "memory" | ||
25 | ); | ||
26 | } else { | ||
27 | __asm__ __volatile__ ( | ||
28 | "stc sr, %0\n\t" | ||
29 | "and %1, %0\n\t" | ||
30 | #ifdef CONFIG_CPU_HAS_SR_RB | ||
31 | "stc r6_bank, %1\n\t" | ||
32 | "or %1, %0\n\t" | ||
33 | #endif | ||
34 | "ldc %0, sr\n\t" | ||
35 | : "=&r" (__dummy0), "=r" (__dummy1) | ||
36 | : "1" (~RAW_IRQ_DISABLED) | ||
37 | : "memory" | ||
38 | ); | ||
39 | } | ||
40 | } | ||
41 | EXPORT_SYMBOL(raw_local_irq_restore); | ||
42 | |||
43 | unsigned long notrace __raw_local_save_flags(void) | ||
44 | { | ||
45 | unsigned long flags; | ||
46 | |||
47 | __asm__ __volatile__ ( | ||
48 | "stc sr, %0\n\t" | ||
49 | "and #0xf0, %0\n\t" | ||
50 | : "=&z" (flags) | ||
51 | : /* no inputs */ | ||
52 | : "memory" | ||
53 | ); | ||
54 | |||
55 | return flags; | ||
56 | } | ||
57 | EXPORT_SYMBOL(__raw_local_save_flags); | ||
diff --git a/arch/sh/kernel/irq_64.c b/arch/sh/kernel/irq_64.c new file mode 100644 index 000000000000..32365ba0e039 --- /dev/null +++ b/arch/sh/kernel/irq_64.c | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * SHmedia irqflags support | ||
3 | * | ||
4 | * Copyright (C) 2006 - 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/irqflags.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <cpu/registers.h> | ||
13 | |||
14 | void notrace raw_local_irq_restore(unsigned long flags) | ||
15 | { | ||
16 | unsigned long long __dummy; | ||
17 | |||
18 | if (flags == RAW_IRQ_DISABLED) { | ||
19 | __asm__ __volatile__ ( | ||
20 | "getcon " __SR ", %0\n\t" | ||
21 | "or %0, %1, %0\n\t" | ||
22 | "putcon %0, " __SR "\n\t" | ||
23 | : "=&r" (__dummy) | ||
24 | : "r" (RAW_IRQ_DISABLED) | ||
25 | ); | ||
26 | } else { | ||
27 | __asm__ __volatile__ ( | ||
28 | "getcon " __SR ", %0\n\t" | ||
29 | "and %0, %1, %0\n\t" | ||
30 | "putcon %0, " __SR "\n\t" | ||
31 | : "=&r" (__dummy) | ||
32 | : "r" (~RAW_IRQ_DISABLED) | ||
33 | ); | ||
34 | } | ||
35 | } | ||
36 | EXPORT_SYMBOL(raw_local_irq_restore); | ||
37 | |||
38 | unsigned long notrace __raw_local_save_flags(void) | ||
39 | { | ||
40 | unsigned long flags; | ||
41 | |||
42 | __asm__ __volatile__ ( | ||
43 | "getcon " __SR ", %0\n\t" | ||
44 | "and %0, %1, %0" | ||
45 | : "=&r" (flags) | ||
46 | : "r" (RAW_IRQ_DISABLED) | ||
47 | ); | ||
48 | |||
49 | return flags; | ||
50 | } | ||
51 | EXPORT_SYMBOL(__raw_local_save_flags); | ||
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c index 7ea2704ea033..76f280223ebd 100644 --- a/arch/sh/kernel/machine_kexec.c +++ b/arch/sh/kernel/machine_kexec.c | |||
@@ -46,12 +46,6 @@ void machine_crash_shutdown(struct pt_regs *regs) | |||
46 | */ | 46 | */ |
47 | int machine_kexec_prepare(struct kimage *image) | 47 | int machine_kexec_prepare(struct kimage *image) |
48 | { | 48 | { |
49 | /* older versions of kexec-tools are passing | ||
50 | * the zImage entry point as a virtual address. | ||
51 | */ | ||
52 | if (image->start != PHYSADDR(image->start)) | ||
53 | return -EINVAL; /* upgrade your kexec-tools */ | ||
54 | |||
55 | return 0; | 49 | return 0; |
56 | } | 50 | } |
57 | 51 | ||
diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c index cbce639b108a..1652340ba3f2 100644 --- a/arch/sh/kernel/machvec.c +++ b/arch/sh/kernel/machvec.c | |||
@@ -135,5 +135,9 @@ void __init sh_mv_setup(void) | |||
135 | if (!sh_mv.mv_nr_irqs) | 135 | if (!sh_mv.mv_nr_irqs) |
136 | sh_mv.mv_nr_irqs = NR_IRQS; | 136 | sh_mv.mv_nr_irqs = NR_IRQS; |
137 | 137 | ||
138 | #ifdef P2SEG | ||
138 | __set_io_port_base(P2SEG); | 139 | __set_io_port_base(P2SEG); |
140 | #else | ||
141 | __set_io_port_base(0); | ||
142 | #endif | ||
139 | } | 143 | } |
diff --git a/arch/sh/kernel/module.c b/arch/sh/kernel/module.c index c2efdcde266f..43adddfe4c04 100644 --- a/arch/sh/kernel/module.c +++ b/arch/sh/kernel/module.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/string.h> | 32 | #include <linux/string.h> |
33 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
34 | #include <asm/unaligned.h> | 34 | #include <asm/unaligned.h> |
35 | #include <asm/dwarf.h> | ||
35 | 36 | ||
36 | void *module_alloc(unsigned long size) | 37 | void *module_alloc(unsigned long size) |
37 | { | 38 | { |
@@ -145,10 +146,16 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
145 | const Elf_Shdr *sechdrs, | 146 | const Elf_Shdr *sechdrs, |
146 | struct module *me) | 147 | struct module *me) |
147 | { | 148 | { |
148 | return module_bug_finalize(hdr, sechdrs, me); | 149 | int ret = 0; |
150 | |||
151 | ret |= module_dwarf_finalize(hdr, sechdrs, me); | ||
152 | ret |= module_bug_finalize(hdr, sechdrs, me); | ||
153 | |||
154 | return ret; | ||
149 | } | 155 | } |
150 | 156 | ||
151 | void module_arch_cleanup(struct module *mod) | 157 | void module_arch_cleanup(struct module *mod) |
152 | { | 158 | { |
153 | module_bug_cleanup(mod); | 159 | module_bug_cleanup(mod); |
160 | module_dwarf_cleanup(mod); | ||
154 | } | 161 | } |
diff --git a/arch/sh/kernel/perf_callchain.c b/arch/sh/kernel/perf_callchain.c new file mode 100644 index 000000000000..24ea837eac5b --- /dev/null +++ b/arch/sh/kernel/perf_callchain.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * Performance event callchain support - SuperH architecture code | ||
3 | * | ||
4 | * Copyright (C) 2009 Paul Mundt | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/perf_event.h> | ||
13 | #include <linux/percpu.h> | ||
14 | #include <asm/unwinder.h> | ||
15 | #include <asm/ptrace.h> | ||
16 | |||
17 | static inline void callchain_store(struct perf_callchain_entry *entry, u64 ip) | ||
18 | { | ||
19 | if (entry->nr < PERF_MAX_STACK_DEPTH) | ||
20 | entry->ip[entry->nr++] = ip; | ||
21 | } | ||
22 | |||
23 | static void callchain_warning(void *data, char *msg) | ||
24 | { | ||
25 | } | ||
26 | |||
27 | static void | ||
28 | callchain_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
29 | { | ||
30 | } | ||
31 | |||
32 | static int callchain_stack(void *data, char *name) | ||
33 | { | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static void callchain_address(void *data, unsigned long addr, int reliable) | ||
38 | { | ||
39 | struct perf_callchain_entry *entry = data; | ||
40 | |||
41 | if (reliable) | ||
42 | callchain_store(entry, addr); | ||
43 | } | ||
44 | |||
45 | static const struct stacktrace_ops callchain_ops = { | ||
46 | .warning = callchain_warning, | ||
47 | .warning_symbol = callchain_warning_symbol, | ||
48 | .stack = callchain_stack, | ||
49 | .address = callchain_address, | ||
50 | }; | ||
51 | |||
52 | static void | ||
53 | perf_callchain_kernel(struct pt_regs *regs, struct perf_callchain_entry *entry) | ||
54 | { | ||
55 | callchain_store(entry, PERF_CONTEXT_KERNEL); | ||
56 | callchain_store(entry, regs->pc); | ||
57 | |||
58 | unwind_stack(NULL, regs, NULL, &callchain_ops, entry); | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | perf_do_callchain(struct pt_regs *regs, struct perf_callchain_entry *entry) | ||
63 | { | ||
64 | int is_user; | ||
65 | |||
66 | if (!regs) | ||
67 | return; | ||
68 | |||
69 | is_user = user_mode(regs); | ||
70 | |||
71 | if (!current || current->pid == 0) | ||
72 | return; | ||
73 | |||
74 | if (is_user && current->state != TASK_RUNNING) | ||
75 | return; | ||
76 | |||
77 | /* | ||
78 | * Only the kernel side is implemented for now. | ||
79 | */ | ||
80 | if (!is_user) | ||
81 | perf_callchain_kernel(regs, entry); | ||
82 | } | ||
83 | |||
84 | /* | ||
85 | * No need for separate IRQ and NMI entries. | ||
86 | */ | ||
87 | static DEFINE_PER_CPU(struct perf_callchain_entry, callchain); | ||
88 | |||
89 | struct perf_callchain_entry *perf_callchain(struct pt_regs *regs) | ||
90 | { | ||
91 | struct perf_callchain_entry *entry = &__get_cpu_var(callchain); | ||
92 | |||
93 | entry->nr = 0; | ||
94 | |||
95 | perf_do_callchain(regs, entry); | ||
96 | |||
97 | return entry; | ||
98 | } | ||
diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c new file mode 100644 index 000000000000..7ff0943e7a08 --- /dev/null +++ b/arch/sh/kernel/perf_event.c | |||
@@ -0,0 +1,312 @@ | |||
1 | /* | ||
2 | * Performance event support framework for SuperH hardware counters. | ||
3 | * | ||
4 | * Copyright (C) 2009 Paul Mundt | ||
5 | * | ||
6 | * Heavily based on the x86 and PowerPC implementations. | ||
7 | * | ||
8 | * x86: | ||
9 | * Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de> | ||
10 | * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar | ||
11 | * Copyright (C) 2009 Jaswinder Singh Rajput | ||
12 | * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter | ||
13 | * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com> | ||
14 | * Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com> | ||
15 | * | ||
16 | * ppc: | ||
17 | * Copyright 2008-2009 Paul Mackerras, IBM Corporation. | ||
18 | * | ||
19 | * This file is subject to the terms and conditions of the GNU General Public | ||
20 | * License. See the file "COPYING" in the main directory of this archive | ||
21 | * for more details. | ||
22 | */ | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/irq.h> | ||
27 | #include <linux/perf_event.h> | ||
28 | #include <asm/processor.h> | ||
29 | |||
30 | struct cpu_hw_events { | ||
31 | struct perf_event *events[MAX_HWEVENTS]; | ||
32 | unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; | ||
33 | unsigned long active_mask[BITS_TO_LONGS(MAX_HWEVENTS)]; | ||
34 | }; | ||
35 | |||
36 | DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); | ||
37 | |||
38 | static struct sh_pmu *sh_pmu __read_mostly; | ||
39 | |||
40 | /* Number of perf_events counting hardware events */ | ||
41 | static atomic_t num_events; | ||
42 | /* Used to avoid races in calling reserve/release_pmc_hardware */ | ||
43 | static DEFINE_MUTEX(pmc_reserve_mutex); | ||
44 | |||
45 | /* | ||
46 | * Stub these out for now, do something more profound later. | ||
47 | */ | ||
48 | int reserve_pmc_hardware(void) | ||
49 | { | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | void release_pmc_hardware(void) | ||
54 | { | ||
55 | } | ||
56 | |||
57 | static inline int sh_pmu_initialized(void) | ||
58 | { | ||
59 | return !!sh_pmu; | ||
60 | } | ||
61 | |||
62 | /* | ||
63 | * Release the PMU if this is the last perf_event. | ||
64 | */ | ||
65 | static void hw_perf_event_destroy(struct perf_event *event) | ||
66 | { | ||
67 | if (!atomic_add_unless(&num_events, -1, 1)) { | ||
68 | mutex_lock(&pmc_reserve_mutex); | ||
69 | if (atomic_dec_return(&num_events) == 0) | ||
70 | release_pmc_hardware(); | ||
71 | mutex_unlock(&pmc_reserve_mutex); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | static int hw_perf_cache_event(int config, int *evp) | ||
76 | { | ||
77 | unsigned long type, op, result; | ||
78 | int ev; | ||
79 | |||
80 | if (!sh_pmu->cache_events) | ||
81 | return -EINVAL; | ||
82 | |||
83 | /* unpack config */ | ||
84 | type = config & 0xff; | ||
85 | op = (config >> 8) & 0xff; | ||
86 | result = (config >> 16) & 0xff; | ||
87 | |||
88 | if (type >= PERF_COUNT_HW_CACHE_MAX || | ||
89 | op >= PERF_COUNT_HW_CACHE_OP_MAX || | ||
90 | result >= PERF_COUNT_HW_CACHE_RESULT_MAX) | ||
91 | return -EINVAL; | ||
92 | |||
93 | ev = (*sh_pmu->cache_events)[type][op][result]; | ||
94 | if (ev == 0) | ||
95 | return -EOPNOTSUPP; | ||
96 | if (ev == -1) | ||
97 | return -EINVAL; | ||
98 | *evp = ev; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int __hw_perf_event_init(struct perf_event *event) | ||
103 | { | ||
104 | struct perf_event_attr *attr = &event->attr; | ||
105 | struct hw_perf_event *hwc = &event->hw; | ||
106 | int config = -1; | ||
107 | int err; | ||
108 | |||
109 | if (!sh_pmu_initialized()) | ||
110 | return -ENODEV; | ||
111 | |||
112 | /* | ||
113 | * All of the on-chip counters are "limited", in that they have | ||
114 | * no interrupts, and are therefore unable to do sampling without | ||
115 | * further work and timer assistance. | ||
116 | */ | ||
117 | if (hwc->sample_period) | ||
118 | return -EINVAL; | ||
119 | |||
120 | /* | ||
121 | * See if we need to reserve the counter. | ||
122 | * | ||
123 | * If no events are currently in use, then we have to take a | ||
124 | * mutex to ensure that we don't race with another task doing | ||
125 | * reserve_pmc_hardware or release_pmc_hardware. | ||
126 | */ | ||
127 | err = 0; | ||
128 | if (!atomic_inc_not_zero(&num_events)) { | ||
129 | mutex_lock(&pmc_reserve_mutex); | ||
130 | if (atomic_read(&num_events) == 0 && | ||
131 | reserve_pmc_hardware()) | ||
132 | err = -EBUSY; | ||
133 | else | ||
134 | atomic_inc(&num_events); | ||
135 | mutex_unlock(&pmc_reserve_mutex); | ||
136 | } | ||
137 | |||
138 | if (err) | ||
139 | return err; | ||
140 | |||
141 | event->destroy = hw_perf_event_destroy; | ||
142 | |||
143 | switch (attr->type) { | ||
144 | case PERF_TYPE_RAW: | ||
145 | config = attr->config & sh_pmu->raw_event_mask; | ||
146 | break; | ||
147 | case PERF_TYPE_HW_CACHE: | ||
148 | err = hw_perf_cache_event(attr->config, &config); | ||
149 | if (err) | ||
150 | return err; | ||
151 | break; | ||
152 | case PERF_TYPE_HARDWARE: | ||
153 | if (attr->config >= sh_pmu->max_events) | ||
154 | return -EINVAL; | ||
155 | |||
156 | config = sh_pmu->event_map(attr->config); | ||
157 | break; | ||
158 | } | ||
159 | |||
160 | if (config == -1) | ||
161 | return -EINVAL; | ||
162 | |||
163 | hwc->config |= config; | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static void sh_perf_event_update(struct perf_event *event, | ||
169 | struct hw_perf_event *hwc, int idx) | ||
170 | { | ||
171 | u64 prev_raw_count, new_raw_count; | ||
172 | s64 delta; | ||
173 | int shift = 0; | ||
174 | |||
175 | /* | ||
176 | * Depending on the counter configuration, they may or may not | ||
177 | * be chained, in which case the previous counter value can be | ||
178 | * updated underneath us if the lower-half overflows. | ||
179 | * | ||
180 | * Our tactic to handle this is to first atomically read and | ||
181 | * exchange a new raw count - then add that new-prev delta | ||
182 | * count to the generic counter atomically. | ||
183 | * | ||
184 | * As there is no interrupt associated with the overflow events, | ||
185 | * this is the simplest approach for maintaining consistency. | ||
186 | */ | ||
187 | again: | ||
188 | prev_raw_count = atomic64_read(&hwc->prev_count); | ||
189 | new_raw_count = sh_pmu->read(idx); | ||
190 | |||
191 | if (atomic64_cmpxchg(&hwc->prev_count, prev_raw_count, | ||
192 | new_raw_count) != prev_raw_count) | ||
193 | goto again; | ||
194 | |||
195 | /* | ||
196 | * Now we have the new raw value and have updated the prev | ||
197 | * timestamp already. We can now calculate the elapsed delta | ||
198 | * (counter-)time and add that to the generic counter. | ||
199 | * | ||
200 | * Careful, not all hw sign-extends above the physical width | ||
201 | * of the count. | ||
202 | */ | ||
203 | delta = (new_raw_count << shift) - (prev_raw_count << shift); | ||
204 | delta >>= shift; | ||
205 | |||
206 | atomic64_add(delta, &event->count); | ||
207 | } | ||
208 | |||
209 | static void sh_pmu_disable(struct perf_event *event) | ||
210 | { | ||
211 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
212 | struct hw_perf_event *hwc = &event->hw; | ||
213 | int idx = hwc->idx; | ||
214 | |||
215 | clear_bit(idx, cpuc->active_mask); | ||
216 | sh_pmu->disable(hwc, idx); | ||
217 | |||
218 | barrier(); | ||
219 | |||
220 | sh_perf_event_update(event, &event->hw, idx); | ||
221 | |||
222 | cpuc->events[idx] = NULL; | ||
223 | clear_bit(idx, cpuc->used_mask); | ||
224 | |||
225 | perf_event_update_userpage(event); | ||
226 | } | ||
227 | |||
228 | static int sh_pmu_enable(struct perf_event *event) | ||
229 | { | ||
230 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
231 | struct hw_perf_event *hwc = &event->hw; | ||
232 | int idx = hwc->idx; | ||
233 | |||
234 | if (test_and_set_bit(idx, cpuc->used_mask)) { | ||
235 | idx = find_first_zero_bit(cpuc->used_mask, sh_pmu->num_events); | ||
236 | if (idx == sh_pmu->num_events) | ||
237 | return -EAGAIN; | ||
238 | |||
239 | set_bit(idx, cpuc->used_mask); | ||
240 | hwc->idx = idx; | ||
241 | } | ||
242 | |||
243 | sh_pmu->disable(hwc, idx); | ||
244 | |||
245 | cpuc->events[idx] = event; | ||
246 | set_bit(idx, cpuc->active_mask); | ||
247 | |||
248 | sh_pmu->enable(hwc, idx); | ||
249 | |||
250 | perf_event_update_userpage(event); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static void sh_pmu_read(struct perf_event *event) | ||
256 | { | ||
257 | sh_perf_event_update(event, &event->hw, event->hw.idx); | ||
258 | } | ||
259 | |||
260 | static const struct pmu pmu = { | ||
261 | .enable = sh_pmu_enable, | ||
262 | .disable = sh_pmu_disable, | ||
263 | .read = sh_pmu_read, | ||
264 | }; | ||
265 | |||
266 | const struct pmu *hw_perf_event_init(struct perf_event *event) | ||
267 | { | ||
268 | int err = __hw_perf_event_init(event); | ||
269 | if (unlikely(err)) { | ||
270 | if (event->destroy) | ||
271 | event->destroy(event); | ||
272 | return ERR_PTR(err); | ||
273 | } | ||
274 | |||
275 | return &pmu; | ||
276 | } | ||
277 | |||
278 | void hw_perf_event_setup(int cpu) | ||
279 | { | ||
280 | struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu); | ||
281 | |||
282 | memset(cpuhw, 0, sizeof(struct cpu_hw_events)); | ||
283 | } | ||
284 | |||
285 | void hw_perf_enable(void) | ||
286 | { | ||
287 | if (!sh_pmu_initialized()) | ||
288 | return; | ||
289 | |||
290 | sh_pmu->enable_all(); | ||
291 | } | ||
292 | |||
293 | void hw_perf_disable(void) | ||
294 | { | ||
295 | if (!sh_pmu_initialized()) | ||
296 | return; | ||
297 | |||
298 | sh_pmu->disable_all(); | ||
299 | } | ||
300 | |||
301 | int register_sh_pmu(struct sh_pmu *pmu) | ||
302 | { | ||
303 | if (sh_pmu) | ||
304 | return -EBUSY; | ||
305 | sh_pmu = pmu; | ||
306 | |||
307 | pr_info("Performance Events: %s support registered\n", pmu->name); | ||
308 | |||
309 | WARN_ON(pmu->num_events > MAX_HWEVENTS); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index 0673c4746be3..d8af889366a4 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c | |||
@@ -134,7 +134,10 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
134 | regs.regs[5] = (unsigned long)fn; | 134 | regs.regs[5] = (unsigned long)fn; |
135 | 135 | ||
136 | regs.pc = (unsigned long)kernel_thread_helper; | 136 | regs.pc = (unsigned long)kernel_thread_helper; |
137 | regs.sr = (1 << 30); | 137 | regs.sr = SR_MD; |
138 | #if defined(CONFIG_SH_FPU) | ||
139 | regs.sr |= SR_FD; | ||
140 | #endif | ||
138 | 141 | ||
139 | /* Ok, create the new process.. */ | 142 | /* Ok, create the new process.. */ |
140 | pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, | 143 | pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, |
@@ -142,6 +145,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
142 | 145 | ||
143 | return pid; | 146 | return pid; |
144 | } | 147 | } |
148 | EXPORT_SYMBOL(kernel_thread); | ||
145 | 149 | ||
146 | /* | 150 | /* |
147 | * Free current thread data structures etc.. | 151 | * Free current thread data structures etc.. |
@@ -186,6 +190,16 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
186 | 190 | ||
187 | return fpvalid; | 191 | return fpvalid; |
188 | } | 192 | } |
193 | EXPORT_SYMBOL(dump_fpu); | ||
194 | |||
195 | /* | ||
196 | * This gets called before we allocate a new thread and copy | ||
197 | * the current task into it. | ||
198 | */ | ||
199 | void prepare_to_copy(struct task_struct *tsk) | ||
200 | { | ||
201 | unlazy_fpu(tsk, task_pt_regs(tsk)); | ||
202 | } | ||
189 | 203 | ||
190 | asmlinkage void ret_from_fork(void); | 204 | asmlinkage void ret_from_fork(void); |
191 | 205 | ||
@@ -195,16 +209,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
195 | { | 209 | { |
196 | struct thread_info *ti = task_thread_info(p); | 210 | struct thread_info *ti = task_thread_info(p); |
197 | struct pt_regs *childregs; | 211 | struct pt_regs *childregs; |
198 | #if defined(CONFIG_SH_FPU) || defined(CONFIG_SH_DSP) | 212 | #if defined(CONFIG_SH_DSP) |
199 | struct task_struct *tsk = current; | 213 | struct task_struct *tsk = current; |
200 | #endif | 214 | #endif |
201 | 215 | ||
202 | #if defined(CONFIG_SH_FPU) | ||
203 | unlazy_fpu(tsk, regs); | ||
204 | p->thread.fpu = tsk->thread.fpu; | ||
205 | copy_to_stopped_child_used_math(p); | ||
206 | #endif | ||
207 | |||
208 | #if defined(CONFIG_SH_DSP) | 216 | #if defined(CONFIG_SH_DSP) |
209 | if (is_dsp_enabled(tsk)) { | 217 | if (is_dsp_enabled(tsk)) { |
210 | /* We can use the __save_dsp or just copy the struct: | 218 | /* We can use the __save_dsp or just copy the struct: |
@@ -224,6 +232,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
224 | } else { | 232 | } else { |
225 | childregs->regs[15] = (unsigned long)childregs; | 233 | childregs->regs[15] = (unsigned long)childregs; |
226 | ti->addr_limit = KERNEL_DS; | 234 | ti->addr_limit = KERNEL_DS; |
235 | ti->status &= ~TS_USEDFPU; | ||
236 | p->fpu_counter = 0; | ||
227 | } | 237 | } |
228 | 238 | ||
229 | if (clone_flags & CLONE_SETTLS) | 239 | if (clone_flags & CLONE_SETTLS) |
@@ -288,9 +298,13 @@ static void ubc_set_tracing(int asid, unsigned long pc) | |||
288 | __notrace_funcgraph struct task_struct * | 298 | __notrace_funcgraph struct task_struct * |
289 | __switch_to(struct task_struct *prev, struct task_struct *next) | 299 | __switch_to(struct task_struct *prev, struct task_struct *next) |
290 | { | 300 | { |
291 | #if defined(CONFIG_SH_FPU) | 301 | struct thread_struct *next_t = &next->thread; |
302 | |||
292 | unlazy_fpu(prev, task_pt_regs(prev)); | 303 | unlazy_fpu(prev, task_pt_regs(prev)); |
293 | #endif | 304 | |
305 | /* we're going to use this soon, after a few expensive things */ | ||
306 | if (next->fpu_counter > 5) | ||
307 | prefetch(&next_t->fpu.hard); | ||
294 | 308 | ||
295 | #ifdef CONFIG_MMU | 309 | #ifdef CONFIG_MMU |
296 | /* | 310 | /* |
@@ -321,6 +335,14 @@ __switch_to(struct task_struct *prev, struct task_struct *next) | |||
321 | #endif | 335 | #endif |
322 | } | 336 | } |
323 | 337 | ||
338 | /* | ||
339 | * If the task has used fpu the last 5 timeslices, just do a full | ||
340 | * restore of the math state immediately to avoid the trap; the | ||
341 | * chances of needing FPU soon are obviously high now | ||
342 | */ | ||
343 | if (next->fpu_counter > 5) | ||
344 | fpu_state_restore(task_pt_regs(next)); | ||
345 | |||
324 | return prev; | 346 | return prev; |
325 | } | 347 | } |
326 | 348 | ||
diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 1192398ef582..359b8a2f4d2e 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c | |||
@@ -335,6 +335,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) | |||
335 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, | 335 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, |
336 | ®s, 0, NULL, NULL); | 336 | ®s, 0, NULL, NULL); |
337 | } | 337 | } |
338 | EXPORT_SYMBOL(kernel_thread); | ||
338 | 339 | ||
339 | /* | 340 | /* |
340 | * Free current thread data structures etc.. | 341 | * Free current thread data structures etc.. |
@@ -417,6 +418,7 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) | |||
417 | return 0; /* Task didn't use the fpu at all. */ | 418 | return 0; /* Task didn't use the fpu at all. */ |
418 | #endif | 419 | #endif |
419 | } | 420 | } |
421 | EXPORT_SYMBOL(dump_fpu); | ||
420 | 422 | ||
421 | asmlinkage void ret_from_fork(void); | 423 | asmlinkage void ret_from_fork(void); |
422 | 424 | ||
diff --git a/arch/sh/kernel/return_address.c b/arch/sh/kernel/return_address.c new file mode 100644 index 000000000000..df3ab5811074 --- /dev/null +++ b/arch/sh/kernel/return_address.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * arch/sh/kernel/return_address.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Matt Fleming | ||
5 | * Copyright (C) 2009 Paul Mundt | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file "COPYING" in the main directory of this archive | ||
9 | * for more details. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <asm/dwarf.h> | ||
13 | |||
14 | #ifdef CONFIG_DWARF_UNWINDER | ||
15 | |||
16 | void *return_address(unsigned int depth) | ||
17 | { | ||
18 | struct dwarf_frame *frame; | ||
19 | unsigned long ra; | ||
20 | int i; | ||
21 | |||
22 | for (i = 0, frame = NULL, ra = 0; i <= depth; i++) { | ||
23 | struct dwarf_frame *tmp; | ||
24 | |||
25 | tmp = dwarf_unwind_stack(ra, frame); | ||
26 | |||
27 | if (frame) | ||
28 | dwarf_free_frame(frame); | ||
29 | |||
30 | frame = tmp; | ||
31 | |||
32 | if (!frame || !frame->return_addr) | ||
33 | break; | ||
34 | |||
35 | ra = frame->return_addr; | ||
36 | } | ||
37 | |||
38 | /* Failed to unwind the stack to the specified depth. */ | ||
39 | WARN_ON(i != depth + 1); | ||
40 | |||
41 | if (frame) | ||
42 | dwarf_free_frame(frame); | ||
43 | |||
44 | return (void *)ra; | ||
45 | } | ||
46 | |||
47 | #else | ||
48 | |||
49 | void *return_address(unsigned int depth) | ||
50 | { | ||
51 | return NULL; | ||
52 | } | ||
53 | |||
54 | #endif | ||
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 99b4fb553bf1..5a947a2567e4 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
@@ -453,6 +453,10 @@ void __init setup_arch(char **cmdline_p) | |||
453 | 453 | ||
454 | paging_init(); | 454 | paging_init(); |
455 | 455 | ||
456 | #ifdef CONFIG_PMB_ENABLE | ||
457 | pmb_init(); | ||
458 | #endif | ||
459 | |||
456 | #ifdef CONFIG_SMP | 460 | #ifdef CONFIG_SMP |
457 | plat_smp_setup(); | 461 | plat_smp_setup(); |
458 | #endif | 462 | #endif |
diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c index 444cce3ae921..3896f26efa4a 100644 --- a/arch/sh/kernel/sh_ksyms_32.c +++ b/arch/sh/kernel/sh_ksyms_32.c | |||
@@ -1,37 +1,11 @@ | |||
1 | #include <linux/module.h> | 1 | #include <linux/module.h> |
2 | #include <linux/smp.h> | 2 | #include <linux/string.h> |
3 | #include <linux/user.h> | 3 | #include <linux/uaccess.h> |
4 | #include <linux/elfcore.h> | 4 | #include <linux/delay.h> |
5 | #include <linux/sched.h> | 5 | #include <linux/mm.h> |
6 | #include <linux/in6.h> | ||
7 | #include <linux/interrupt.h> | ||
8 | #include <linux/vmalloc.h> | ||
9 | #include <linux/pci.h> | ||
10 | #include <linux/irq.h> | ||
11 | #include <asm/sections.h> | ||
12 | #include <asm/processor.h> | ||
13 | #include <asm/uaccess.h> | ||
14 | #include <asm/checksum.h> | 6 | #include <asm/checksum.h> |
15 | #include <asm/io.h> | 7 | #include <asm/sections.h> |
16 | #include <asm/delay.h> | ||
17 | #include <asm/tlbflush.h> | ||
18 | #include <asm/cacheflush.h> | ||
19 | #include <asm/ftrace.h> | ||
20 | |||
21 | extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); | ||
22 | |||
23 | /* platform dependent support */ | ||
24 | EXPORT_SYMBOL(dump_fpu); | ||
25 | EXPORT_SYMBOL(kernel_thread); | ||
26 | EXPORT_SYMBOL(strlen); | ||
27 | |||
28 | /* PCI exports */ | ||
29 | #ifdef CONFIG_PCI | ||
30 | EXPORT_SYMBOL(pci_alloc_consistent); | ||
31 | EXPORT_SYMBOL(pci_free_consistent); | ||
32 | #endif | ||
33 | 8 | ||
34 | /* mem exports */ | ||
35 | EXPORT_SYMBOL(memchr); | 9 | EXPORT_SYMBOL(memchr); |
36 | EXPORT_SYMBOL(memcpy); | 10 | EXPORT_SYMBOL(memcpy); |
37 | EXPORT_SYMBOL(memset); | 11 | EXPORT_SYMBOL(memset); |
@@ -40,6 +14,13 @@ EXPORT_SYMBOL(__copy_user); | |||
40 | EXPORT_SYMBOL(__udelay); | 14 | EXPORT_SYMBOL(__udelay); |
41 | EXPORT_SYMBOL(__ndelay); | 15 | EXPORT_SYMBOL(__ndelay); |
42 | EXPORT_SYMBOL(__const_udelay); | 16 | EXPORT_SYMBOL(__const_udelay); |
17 | EXPORT_SYMBOL(strlen); | ||
18 | EXPORT_SYMBOL(csum_partial); | ||
19 | EXPORT_SYMBOL(csum_partial_copy_generic); | ||
20 | EXPORT_SYMBOL(copy_page); | ||
21 | EXPORT_SYMBOL(__clear_user); | ||
22 | EXPORT_SYMBOL(_ebss); | ||
23 | EXPORT_SYMBOL(empty_zero_page); | ||
43 | 24 | ||
44 | #define DECLARE_EXPORT(name) \ | 25 | #define DECLARE_EXPORT(name) \ |
45 | extern void name(void);EXPORT_SYMBOL(name) | 26 | extern void name(void);EXPORT_SYMBOL(name) |
@@ -107,30 +88,6 @@ DECLARE_EXPORT(__sdivsi3_i4); | |||
107 | DECLARE_EXPORT(__udivsi3_i4); | 88 | DECLARE_EXPORT(__udivsi3_i4); |
108 | DECLARE_EXPORT(__sdivsi3_i4i); | 89 | DECLARE_EXPORT(__sdivsi3_i4i); |
109 | DECLARE_EXPORT(__udivsi3_i4i); | 90 | DECLARE_EXPORT(__udivsi3_i4i); |
110 | |||
111 | #if !defined(CONFIG_CACHE_OFF) && (defined(CONFIG_CPU_SH4) || \ | ||
112 | defined(CONFIG_SH7705_CACHE_32KB)) | ||
113 | /* needed by some modules */ | ||
114 | EXPORT_SYMBOL(flush_cache_all); | ||
115 | EXPORT_SYMBOL(flush_cache_range); | ||
116 | EXPORT_SYMBOL(flush_dcache_page); | ||
117 | #endif | ||
118 | |||
119 | #ifdef CONFIG_MCOUNT | 91 | #ifdef CONFIG_MCOUNT |
120 | DECLARE_EXPORT(mcount); | 92 | DECLARE_EXPORT(mcount); |
121 | #endif | 93 | #endif |
122 | EXPORT_SYMBOL(csum_partial); | ||
123 | EXPORT_SYMBOL(csum_partial_copy_generic); | ||
124 | #ifdef CONFIG_IPV6 | ||
125 | EXPORT_SYMBOL(csum_ipv6_magic); | ||
126 | #endif | ||
127 | EXPORT_SYMBOL(copy_page); | ||
128 | EXPORT_SYMBOL(__clear_user); | ||
129 | EXPORT_SYMBOL(_ebss); | ||
130 | EXPORT_SYMBOL(empty_zero_page); | ||
131 | |||
132 | #ifndef CONFIG_CACHE_OFF | ||
133 | EXPORT_SYMBOL(__flush_purge_region); | ||
134 | EXPORT_SYMBOL(__flush_wback_region); | ||
135 | EXPORT_SYMBOL(__flush_invalidate_region); | ||
136 | #endif | ||
diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c index d008e17eb257..45afa5c51f67 100644 --- a/arch/sh/kernel/sh_ksyms_64.c +++ b/arch/sh/kernel/sh_ksyms_64.c | |||
@@ -24,16 +24,6 @@ | |||
24 | #include <asm/delay.h> | 24 | #include <asm/delay.h> |
25 | #include <asm/irq.h> | 25 | #include <asm/irq.h> |
26 | 26 | ||
27 | extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); | ||
28 | |||
29 | /* platform dependent support */ | ||
30 | EXPORT_SYMBOL(dump_fpu); | ||
31 | EXPORT_SYMBOL(kernel_thread); | ||
32 | |||
33 | #ifdef CONFIG_VT | ||
34 | EXPORT_SYMBOL(screen_info); | ||
35 | #endif | ||
36 | |||
37 | EXPORT_SYMBOL(__put_user_asm_b); | 27 | EXPORT_SYMBOL(__put_user_asm_b); |
38 | EXPORT_SYMBOL(__put_user_asm_w); | 28 | EXPORT_SYMBOL(__put_user_asm_w); |
39 | EXPORT_SYMBOL(__put_user_asm_l); | 29 | EXPORT_SYMBOL(__put_user_asm_l); |
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index 3db37425210d..12815ce01ecd 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c | |||
@@ -67,7 +67,8 @@ sys_sigsuspend(old_sigset_t mask, | |||
67 | 67 | ||
68 | current->state = TASK_INTERRUPTIBLE; | 68 | current->state = TASK_INTERRUPTIBLE; |
69 | schedule(); | 69 | schedule(); |
70 | set_thread_flag(TIF_RESTORE_SIGMASK); | 70 | set_restore_sigmask(); |
71 | |||
71 | return -ERESTARTNOHAND; | 72 | return -ERESTARTNOHAND; |
72 | } | 73 | } |
73 | 74 | ||
@@ -590,7 +591,7 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) | |||
590 | if (try_to_freeze()) | 591 | if (try_to_freeze()) |
591 | goto no_signal; | 592 | goto no_signal; |
592 | 593 | ||
593 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 594 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) |
594 | oldset = ¤t->saved_sigmask; | 595 | oldset = ¤t->saved_sigmask; |
595 | else | 596 | else |
596 | oldset = ¤t->blocked; | 597 | oldset = ¤t->blocked; |
@@ -602,12 +603,13 @@ static void do_signal(struct pt_regs *regs, unsigned int save_r0) | |||
602 | /* Whee! Actually deliver the signal. */ | 603 | /* Whee! Actually deliver the signal. */ |
603 | if (handle_signal(signr, &ka, &info, oldset, | 604 | if (handle_signal(signr, &ka, &info, oldset, |
604 | regs, save_r0) == 0) { | 605 | regs, save_r0) == 0) { |
605 | /* a signal was successfully delivered; the saved | 606 | /* |
607 | * A signal was successfully delivered; the saved | ||
606 | * sigmask will have been stored in the signal frame, | 608 | * sigmask will have been stored in the signal frame, |
607 | * and will be restored by sigreturn, so we can simply | 609 | * and will be restored by sigreturn, so we can simply |
608 | * clear the TIF_RESTORE_SIGMASK flag */ | 610 | * clear the TS_RESTORE_SIGMASK flag |
609 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 611 | */ |
610 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 612 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
611 | 613 | ||
612 | tracehook_signal_handler(signr, &info, &ka, regs, | 614 | tracehook_signal_handler(signr, &info, &ka, regs, |
613 | test_thread_flag(TIF_SINGLESTEP)); | 615 | test_thread_flag(TIF_SINGLESTEP)); |
@@ -631,10 +633,12 @@ no_signal: | |||
631 | } | 633 | } |
632 | } | 634 | } |
633 | 635 | ||
634 | /* if there's no signal to deliver, we just put the saved sigmask | 636 | /* |
635 | * back */ | 637 | * If there's no signal to deliver, we just put the saved sigmask |
636 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | 638 | * back. |
637 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 639 | */ |
640 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) { | ||
641 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; | ||
638 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 642 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
639 | } | 643 | } |
640 | } | 644 | } |
diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 74793c80a57a..feb3dddd3192 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c | |||
@@ -101,7 +101,7 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
101 | if (try_to_freeze()) | 101 | if (try_to_freeze()) |
102 | goto no_signal; | 102 | goto no_signal; |
103 | 103 | ||
104 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 104 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) |
105 | oldset = ¤t->saved_sigmask; | 105 | oldset = ¤t->saved_sigmask; |
106 | else if (!oldset) | 106 | else if (!oldset) |
107 | oldset = ¤t->blocked; | 107 | oldset = ¤t->blocked; |
@@ -115,11 +115,9 @@ static int do_signal(struct pt_regs *regs, sigset_t *oldset) | |||
115 | /* | 115 | /* |
116 | * If a signal was successfully delivered, the | 116 | * If a signal was successfully delivered, the |
117 | * saved sigmask is in its frame, and we can | 117 | * saved sigmask is in its frame, and we can |
118 | * clear the TIF_RESTORE_SIGMASK flag. | 118 | * clear the TS_RESTORE_SIGMASK flag. |
119 | */ | 119 | */ |
120 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 120 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
121 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
122 | |||
123 | tracehook_signal_handler(signr, &info, &ka, regs, 0); | 121 | tracehook_signal_handler(signr, &info, &ka, regs, 0); |
124 | return 1; | 122 | return 1; |
125 | } | 123 | } |
@@ -146,8 +144,8 @@ no_signal: | |||
146 | } | 144 | } |
147 | 145 | ||
148 | /* No signal to deliver -- put the saved sigmask back */ | 146 | /* No signal to deliver -- put the saved sigmask back */ |
149 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | 147 | if (current_thread_info()->status & TS_RESTORE_SIGMASK) { |
150 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 148 | current_thread_info()->status &= ~TS_RESTORE_SIGMASK; |
151 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 149 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
152 | } | 150 | } |
153 | 151 | ||
@@ -176,6 +174,7 @@ sys_sigsuspend(old_sigset_t mask, | |||
176 | while (1) { | 174 | while (1) { |
177 | current->state = TASK_INTERRUPTIBLE; | 175 | current->state = TASK_INTERRUPTIBLE; |
178 | schedule(); | 176 | schedule(); |
177 | set_restore_sigmask(); | ||
179 | regs->pc += 4; /* because sys_sigreturn decrements the pc */ | 178 | regs->pc += 4; /* because sys_sigreturn decrements the pc */ |
180 | if (do_signal(regs, &saveset)) { | 179 | if (do_signal(regs, &saveset)) { |
181 | /* pc now points at signal handler. Need to decrement | 180 | /* pc now points at signal handler. Need to decrement |
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 160db1003cfb..983e0792d5f3 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c | |||
@@ -122,7 +122,9 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
122 | stack_start.bss_start = 0; /* don't clear bss for secondary cpus */ | 122 | stack_start.bss_start = 0; /* don't clear bss for secondary cpus */ |
123 | stack_start.start_kernel_fn = start_secondary; | 123 | stack_start.start_kernel_fn = start_secondary; |
124 | 124 | ||
125 | flush_cache_all(); | 125 | flush_icache_range((unsigned long)&stack_start, |
126 | (unsigned long)&stack_start + sizeof(stack_start)); | ||
127 | wmb(); | ||
126 | 128 | ||
127 | plat_start_cpu(cpu, (unsigned long)_stext); | 129 | plat_start_cpu(cpu, (unsigned long)_stext); |
128 | 130 | ||
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index 8aa5d1ceaf14..71399cde03b5 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c | |||
@@ -28,37 +28,13 @@ | |||
28 | #include <asm/cacheflush.h> | 28 | #include <asm/cacheflush.h> |
29 | #include <asm/cachectl.h> | 29 | #include <asm/cachectl.h> |
30 | 30 | ||
31 | static inline long | ||
32 | do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, | ||
33 | unsigned long flags, int fd, unsigned long pgoff) | ||
34 | { | ||
35 | int error = -EBADF; | ||
36 | struct file *file = NULL; | ||
37 | |||
38 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | ||
39 | if (!(flags & MAP_ANONYMOUS)) { | ||
40 | file = fget(fd); | ||
41 | if (!file) | ||
42 | goto out; | ||
43 | } | ||
44 | |||
45 | down_write(¤t->mm->mmap_sem); | ||
46 | error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); | ||
47 | up_write(¤t->mm->mmap_sem); | ||
48 | |||
49 | if (file) | ||
50 | fput(file); | ||
51 | out: | ||
52 | return error; | ||
53 | } | ||
54 | |||
55 | asmlinkage int old_mmap(unsigned long addr, unsigned long len, | 31 | asmlinkage int old_mmap(unsigned long addr, unsigned long len, |
56 | unsigned long prot, unsigned long flags, | 32 | unsigned long prot, unsigned long flags, |
57 | int fd, unsigned long off) | 33 | int fd, unsigned long off) |
58 | { | 34 | { |
59 | if (off & ~PAGE_MASK) | 35 | if (off & ~PAGE_MASK) |
60 | return -EINVAL; | 36 | return -EINVAL; |
61 | return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT); | 37 | return sys_mmap_pgoff(addr, len, prot, flags, fd, off>>PAGE_SHIFT); |
62 | } | 38 | } |
63 | 39 | ||
64 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | 40 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, |
@@ -74,7 +50,7 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | |||
74 | 50 | ||
75 | pgoff >>= PAGE_SHIFT - 12; | 51 | pgoff >>= PAGE_SHIFT - 12; |
76 | 52 | ||
77 | return do_mmap2(addr, len, prot, flags, fd, pgoff); | 53 | return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); |
78 | } | 54 | } |
79 | 55 | ||
80 | /* | 56 | /* |
diff --git a/arch/sh/kernel/topology.c b/arch/sh/kernel/topology.c index 0838942b7083..9b0b633b6c92 100644 --- a/arch/sh/kernel/topology.c +++ b/arch/sh/kernel/topology.c | |||
@@ -16,6 +16,32 @@ | |||
16 | 16 | ||
17 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 17 | static DEFINE_PER_CPU(struct cpu, cpu_devices); |
18 | 18 | ||
19 | cpumask_t cpu_core_map[NR_CPUS]; | ||
20 | |||
21 | static cpumask_t cpu_coregroup_map(unsigned int cpu) | ||
22 | { | ||
23 | /* | ||
24 | * Presently all SH-X3 SMP cores are multi-cores, so just keep it | ||
25 | * simple until we have a method for determining topology.. | ||
26 | */ | ||
27 | return cpu_possible_map; | ||
28 | } | ||
29 | |||
30 | const struct cpumask *cpu_coregroup_mask(unsigned int cpu) | ||
31 | { | ||
32 | return &cpu_core_map[cpu]; | ||
33 | } | ||
34 | |||
35 | int arch_update_cpu_topology(void) | ||
36 | { | ||
37 | unsigned int cpu; | ||
38 | |||
39 | for_each_possible_cpu(cpu) | ||
40 | cpu_core_map[cpu] = cpu_coregroup_map(cpu); | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
19 | static int __init topology_init(void) | 45 | static int __init topology_init(void) |
20 | { | 46 | { |
21 | int i, ret; | 47 | int i, ret; |
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c index a8396f36bd14..7b036339dc92 100644 --- a/arch/sh/kernel/traps.c +++ b/arch/sh/kernel/traps.c | |||
@@ -9,8 +9,8 @@ | |||
9 | #include <asm/unwinder.h> | 9 | #include <asm/unwinder.h> |
10 | #include <asm/system.h> | 10 | #include <asm/system.h> |
11 | 11 | ||
12 | #ifdef CONFIG_BUG | 12 | #ifdef CONFIG_GENERIC_BUG |
13 | void handle_BUG(struct pt_regs *regs) | 13 | static void handle_BUG(struct pt_regs *regs) |
14 | { | 14 | { |
15 | const struct bug_entry *bug; | 15 | const struct bug_entry *bug; |
16 | unsigned long bugaddr = regs->pc; | 16 | unsigned long bugaddr = regs->pc; |
@@ -81,7 +81,7 @@ BUILD_TRAP_HANDLER(bug) | |||
81 | SIGTRAP) == NOTIFY_STOP) | 81 | SIGTRAP) == NOTIFY_STOP) |
82 | return; | 82 | return; |
83 | 83 | ||
84 | #ifdef CONFIG_BUG | 84 | #ifdef CONFIG_GENERIC_BUG |
85 | if (__kernel_text_address(instruction_pointer(regs))) { | 85 | if (__kernel_text_address(instruction_pointer(regs))) { |
86 | insn_size_t insn = *(insn_size_t *)instruction_pointer(regs); | 86 | insn_size_t insn = *(insn_size_t *)instruction_pointer(regs); |
87 | if (insn == TRAPA_BUG_OPCODE) | 87 | if (insn == TRAPA_BUG_OPCODE) |
@@ -95,9 +95,11 @@ BUILD_TRAP_HANDLER(bug) | |||
95 | 95 | ||
96 | BUILD_TRAP_HANDLER(nmi) | 96 | BUILD_TRAP_HANDLER(nmi) |
97 | { | 97 | { |
98 | unsigned int cpu = smp_processor_id(); | ||
98 | TRAP_HANDLER_DECL; | 99 | TRAP_HANDLER_DECL; |
99 | 100 | ||
100 | nmi_enter(); | 101 | nmi_enter(); |
102 | nmi_count(cpu)++; | ||
101 | 103 | ||
102 | switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) { | 104 | switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) { |
103 | case NOTIFY_OK: | 105 | case NOTIFY_OK: |
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 7a2ee3a6b8e7..3da5a125d884 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/kexec.h> | 25 | #include <linux/kexec.h> |
26 | #include <linux/limits.h> | 26 | #include <linux/limits.h> |
27 | #include <linux/proc_fs.h> | 27 | #include <linux/proc_fs.h> |
28 | #include <linux/seq_file.h> | ||
28 | #include <linux/sysfs.h> | 29 | #include <linux/sysfs.h> |
29 | #include <asm/system.h> | 30 | #include <asm/system.h> |
30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
@@ -68,61 +69,49 @@ static const char *se_usermode_action[] = { | |||
68 | "signal+warn" | 69 | "signal+warn" |
69 | }; | 70 | }; |
70 | 71 | ||
71 | static int | 72 | static int alignment_proc_show(struct seq_file *m, void *v) |
72 | proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, | ||
73 | void *data) | ||
74 | { | 73 | { |
75 | char *p = page; | 74 | seq_printf(m, "User:\t\t%lu\n", se_user); |
76 | int len; | 75 | seq_printf(m, "System:\t\t%lu\n", se_sys); |
77 | 76 | seq_printf(m, "Half:\t\t%lu\n", se_half); | |
78 | p += sprintf(p, "User:\t\t%lu\n", se_user); | 77 | seq_printf(m, "Word:\t\t%lu\n", se_word); |
79 | p += sprintf(p, "System:\t\t%lu\n", se_sys); | 78 | seq_printf(m, "DWord:\t\t%lu\n", se_dword); |
80 | p += sprintf(p, "Half:\t\t%lu\n", se_half); | 79 | seq_printf(m, "Multi:\t\t%lu\n", se_multi); |
81 | p += sprintf(p, "Word:\t\t%lu\n", se_word); | 80 | seq_printf(m, "User faults:\t%i (%s)\n", se_usermode, |
82 | p += sprintf(p, "DWord:\t\t%lu\n", se_dword); | ||
83 | p += sprintf(p, "Multi:\t\t%lu\n", se_multi); | ||
84 | p += sprintf(p, "User faults:\t%i (%s)\n", se_usermode, | ||
85 | se_usermode_action[se_usermode]); | 81 | se_usermode_action[se_usermode]); |
86 | p += sprintf(p, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn, | 82 | seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn, |
87 | se_kernmode_warn ? "+warn" : ""); | 83 | se_kernmode_warn ? "+warn" : ""); |
88 | 84 | return 0; | |
89 | len = (p - page) - off; | ||
90 | if (len < 0) | ||
91 | len = 0; | ||
92 | |||
93 | *eof = (len <= count) ? 1 : 0; | ||
94 | *start = page + off; | ||
95 | |||
96 | return len; | ||
97 | } | 85 | } |
98 | 86 | ||
99 | static int proc_alignment_write(struct file *file, const char __user *buffer, | 87 | static int alignment_proc_open(struct inode *inode, struct file *file) |
100 | unsigned long count, void *data) | ||
101 | { | 88 | { |
102 | char mode; | 89 | return single_open(file, alignment_proc_show, NULL); |
103 | |||
104 | if (count > 0) { | ||
105 | if (get_user(mode, buffer)) | ||
106 | return -EFAULT; | ||
107 | if (mode >= '0' && mode <= '5') | ||
108 | se_usermode = mode - '0'; | ||
109 | } | ||
110 | return count; | ||
111 | } | 90 | } |
112 | 91 | ||
113 | static int proc_alignment_kern_write(struct file *file, const char __user *buffer, | 92 | static ssize_t alignment_proc_write(struct file *file, |
114 | unsigned long count, void *data) | 93 | const char __user *buffer, size_t count, loff_t *pos) |
115 | { | 94 | { |
95 | int *data = PDE(file->f_path.dentry->d_inode)->data; | ||
116 | char mode; | 96 | char mode; |
117 | 97 | ||
118 | if (count > 0) { | 98 | if (count > 0) { |
119 | if (get_user(mode, buffer)) | 99 | if (get_user(mode, buffer)) |
120 | return -EFAULT; | 100 | return -EFAULT; |
121 | if (mode >= '0' && mode <= '1') | 101 | if (mode >= '0' && mode <= '5') |
122 | se_kernmode_warn = mode - '0'; | 102 | *data = mode - '0'; |
123 | } | 103 | } |
124 | return count; | 104 | return count; |
125 | } | 105 | } |
106 | |||
107 | static const struct file_operations alignment_proc_fops = { | ||
108 | .owner = THIS_MODULE, | ||
109 | .open = alignment_proc_open, | ||
110 | .read = seq_read, | ||
111 | .llseek = seq_lseek, | ||
112 | .release = single_release, | ||
113 | .write = alignment_proc_write, | ||
114 | }; | ||
126 | #endif | 115 | #endif |
127 | 116 | ||
128 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top) | 117 | static void dump_mem(const char *str, unsigned long bottom, unsigned long top) |
@@ -945,14 +934,9 @@ void __init trap_init(void) | |||
945 | set_exception_table_evt(0x800, do_reserved_inst); | 934 | set_exception_table_evt(0x800, do_reserved_inst); |
946 | set_exception_table_evt(0x820, do_illegal_slot_inst); | 935 | set_exception_table_evt(0x820, do_illegal_slot_inst); |
947 | #elif defined(CONFIG_SH_FPU) | 936 | #elif defined(CONFIG_SH_FPU) |
948 | #ifdef CONFIG_CPU_SUBTYPE_SHX3 | ||
949 | set_exception_table_evt(0xd80, fpu_state_restore_trap_handler); | ||
950 | set_exception_table_evt(0xda0, fpu_state_restore_trap_handler); | ||
951 | #else | ||
952 | set_exception_table_evt(0x800, fpu_state_restore_trap_handler); | 937 | set_exception_table_evt(0x800, fpu_state_restore_trap_handler); |
953 | set_exception_table_evt(0x820, fpu_state_restore_trap_handler); | 938 | set_exception_table_evt(0x820, fpu_state_restore_trap_handler); |
954 | #endif | 939 | #endif |
955 | #endif | ||
956 | 940 | ||
957 | #ifdef CONFIG_CPU_SH2 | 941 | #ifdef CONFIG_CPU_SH2 |
958 | set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler); | 942 | set_exception_table_vec(TRAP_ADDRESS_ERROR, address_error_trap_handler); |
@@ -1011,20 +995,16 @@ static int __init alignment_init(void) | |||
1011 | if (!dir) | 995 | if (!dir) |
1012 | return -ENOMEM; | 996 | return -ENOMEM; |
1013 | 997 | ||
1014 | res = create_proc_entry("alignment", S_IWUSR | S_IRUGO, dir); | 998 | res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir, |
999 | &alignment_proc_fops, &se_usermode); | ||
1015 | if (!res) | 1000 | if (!res) |
1016 | return -ENOMEM; | 1001 | return -ENOMEM; |
1017 | 1002 | ||
1018 | res->read_proc = proc_alignment_read; | 1003 | res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir, |
1019 | res->write_proc = proc_alignment_write; | 1004 | &alignment_proc_fops, &se_kernmode_warn); |
1020 | |||
1021 | res = create_proc_entry("kernel_alignment", S_IWUSR | S_IRUGO, dir); | ||
1022 | if (!res) | 1005 | if (!res) |
1023 | return -ENOMEM; | 1006 | return -ENOMEM; |
1024 | 1007 | ||
1025 | res->read_proc = proc_alignment_read; | ||
1026 | res->write_proc = proc_alignment_kern_write; | ||
1027 | |||
1028 | return 0; | 1008 | return 0; |
1029 | } | 1009 | } |
1030 | 1010 | ||
diff --git a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile index a969b47c5463..dab4d2129812 100644 --- a/arch/sh/lib/Makefile +++ b/arch/sh/lib/Makefile | |||
@@ -2,7 +2,7 @@ | |||
2 | # Makefile for SuperH-specific library files.. | 2 | # Makefile for SuperH-specific library files.. |
3 | # | 3 | # |
4 | 4 | ||
5 | lib-y = delay.o memset.o memmove.o memchr.o \ | 5 | lib-y = delay.o memmove.o memchr.o \ |
6 | checksum.o strlen.o div64.o div64-generic.o | 6 | checksum.o strlen.o div64.o div64-generic.o |
7 | 7 | ||
8 | # Extracted from libgcc | 8 | # Extracted from libgcc |
@@ -23,8 +23,11 @@ obj-y += io.o | |||
23 | memcpy-y := memcpy.o | 23 | memcpy-y := memcpy.o |
24 | memcpy-$(CONFIG_CPU_SH4) := memcpy-sh4.o | 24 | memcpy-$(CONFIG_CPU_SH4) := memcpy-sh4.o |
25 | 25 | ||
26 | memset-y := memset.o | ||
27 | memset-$(CONFIG_CPU_SH4) := memset-sh4.o | ||
28 | |||
26 | lib-$(CONFIG_MMU) += copy_page.o __clear_user.o | 29 | lib-$(CONFIG_MMU) += copy_page.o __clear_user.o |
27 | lib-$(CONFIG_MCOUNT) += mcount.o | 30 | lib-$(CONFIG_MCOUNT) += mcount.o |
28 | lib-y += $(memcpy-y) $(udivsi3-y) | 31 | lib-y += $(memcpy-y) $(memset-y) $(udivsi3-y) |
29 | 32 | ||
30 | EXTRA_CFLAGS += -Werror | 33 | EXTRA_CFLAGS += -Werror |
diff --git a/arch/sh/lib/memset-sh4.S b/arch/sh/lib/memset-sh4.S new file mode 100644 index 000000000000..1a6e32cc4e4d --- /dev/null +++ b/arch/sh/lib/memset-sh4.S | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * "memset" implementation for SH4 | ||
3 | * | ||
4 | * Copyright (C) 1999 Niibe Yutaka | ||
5 | * Copyright (c) 2009 STMicroelectronics Limited | ||
6 | * Author: Stuart Menefy <stuart.menefy:st.com> | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * void *memset(void *s, int c, size_t n); | ||
11 | */ | ||
12 | |||
13 | #include <linux/linkage.h> | ||
14 | |||
15 | ENTRY(memset) | ||
16 | mov #12,r0 | ||
17 | add r6,r4 | ||
18 | cmp/gt r6,r0 | ||
19 | bt/s 40f ! if it's too small, set a byte at once | ||
20 | mov r4,r0 | ||
21 | and #3,r0 | ||
22 | cmp/eq #0,r0 | ||
23 | bt/s 2f ! It's aligned | ||
24 | sub r0,r6 | ||
25 | 1: | ||
26 | dt r0 | ||
27 | bf/s 1b | ||
28 | mov.b r5,@-r4 | ||
29 | 2: ! make VVVV | ||
30 | extu.b r5,r5 | ||
31 | swap.b r5,r0 ! V0 | ||
32 | or r0,r5 ! VV | ||
33 | swap.w r5,r0 ! VV00 | ||
34 | or r0,r5 ! VVVV | ||
35 | |||
36 | ! Check if enough bytes need to be copied to be worth the big loop | ||
37 | mov #0x40, r0 ! (MT) | ||
38 | cmp/gt r6,r0 ! (MT) 64 > len => slow loop | ||
39 | |||
40 | bt/s 22f | ||
41 | mov r6,r0 | ||
42 | |||
43 | ! align the dst to the cache block size if necessary | ||
44 | mov r4, r3 | ||
45 | mov #~(0x1f), r1 | ||
46 | |||
47 | and r3, r1 | ||
48 | cmp/eq r3, r1 | ||
49 | |||
50 | bt/s 11f ! dst is already aligned | ||
51 | sub r1, r3 ! r3-r1 -> r3 | ||
52 | shlr2 r3 ! number of loops | ||
53 | |||
54 | 10: mov.l r5,@-r4 | ||
55 | dt r3 | ||
56 | bf/s 10b | ||
57 | add #-4, r6 | ||
58 | |||
59 | 11: ! dst is 32byte aligned | ||
60 | mov r6,r2 | ||
61 | mov #-5,r0 | ||
62 | shld r0,r2 ! number of loops | ||
63 | |||
64 | add #-32, r4 | ||
65 | mov r5, r0 | ||
66 | 12: | ||
67 | movca.l r0,@r4 | ||
68 | mov.l r5,@(4, r4) | ||
69 | mov.l r5,@(8, r4) | ||
70 | mov.l r5,@(12,r4) | ||
71 | mov.l r5,@(16,r4) | ||
72 | mov.l r5,@(20,r4) | ||
73 | add #-0x20, r6 | ||
74 | mov.l r5,@(24,r4) | ||
75 | dt r2 | ||
76 | mov.l r5,@(28,r4) | ||
77 | bf/s 12b | ||
78 | add #-32, r4 | ||
79 | |||
80 | add #32, r4 | ||
81 | mov #8, r0 | ||
82 | cmp/ge r0, r6 | ||
83 | bf 40f | ||
84 | |||
85 | mov r6,r0 | ||
86 | 22: | ||
87 | shlr2 r0 | ||
88 | shlr r0 ! r0 = r6 >> 3 | ||
89 | 3: | ||
90 | dt r0 | ||
91 | mov.l r5,@-r4 ! set 8-byte at once | ||
92 | bf/s 3b | ||
93 | mov.l r5,@-r4 | ||
94 | ! | ||
95 | mov #7,r0 | ||
96 | and r0,r6 | ||
97 | |||
98 | ! fill bytes (length may be zero) | ||
99 | 40: tst r6,r6 | ||
100 | bt 5f | ||
101 | 4: | ||
102 | dt r6 | ||
103 | bf/s 4b | ||
104 | mov.b r5,@-r4 | ||
105 | 5: | ||
106 | rts | ||
107 | mov r4,r0 | ||
diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c index ac2d7abd2567..d6c15cae0912 100644 --- a/arch/sh/math-emu/math.c +++ b/arch/sh/math-emu/math.c | |||
@@ -558,7 +558,7 @@ static int ieee_fpe_handler(struct pt_regs *regs) | |||
558 | (finsn >> 8) & 0xf); | 558 | (finsn >> 8) & 0xf); |
559 | tsk->thread.fpu.hard.fpscr &= | 559 | tsk->thread.fpu.hard.fpscr &= |
560 | ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); | 560 | ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); |
561 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 561 | task_thread_info(tsk)->status |= TS_USEDFPU; |
562 | } else { | 562 | } else { |
563 | info.si_signo = SIGFPE; | 563 | info.si_signo = SIGFPE; |
564 | info.si_errno = 0; | 564 | info.si_errno = 0; |
@@ -619,10 +619,10 @@ int do_fpu_inst(unsigned short inst, struct pt_regs *regs) | |||
619 | struct task_struct *tsk = current; | 619 | struct task_struct *tsk = current; |
620 | struct sh_fpu_soft_struct *fpu = &(tsk->thread.fpu.soft); | 620 | struct sh_fpu_soft_struct *fpu = &(tsk->thread.fpu.soft); |
621 | 621 | ||
622 | if (!test_tsk_thread_flag(tsk, TIF_USEDFPU)) { | 622 | if (!(task_thread_info(tsk)->status & TS_USEDFPU)) { |
623 | /* initialize once. */ | 623 | /* initialize once. */ |
624 | fpu_init(fpu); | 624 | fpu_init(fpu); |
625 | set_tsk_thread_flag(tsk, TIF_USEDFPU); | 625 | task_thread_info(tsk)->status |= TS_USEDFPU; |
626 | } | 626 | } |
627 | 627 | ||
628 | return fpu_emulate(inst, fpu, regs); | 628 | return fpu_emulate(inst, fpu, regs); |
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig index 7f7b52f9beba..0e7ba8e891cf 100644 --- a/arch/sh/mm/Kconfig +++ b/arch/sh/mm/Kconfig | |||
@@ -82,8 +82,7 @@ config 32BIT | |||
82 | 82 | ||
83 | config PMB_ENABLE | 83 | config PMB_ENABLE |
84 | bool "Support 32-bit physical addressing through PMB" | 84 | bool "Support 32-bit physical addressing through PMB" |
85 | depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785) | 85 | depends on MMU && EXPERIMENTAL && CPU_SH4A |
86 | select 32BIT | ||
87 | default y | 86 | default y |
88 | help | 87 | help |
89 | If you say Y here, physical addressing will be extended to | 88 | If you say Y here, physical addressing will be extended to |
@@ -97,8 +96,7 @@ choice | |||
97 | 96 | ||
98 | config PMB | 97 | config PMB |
99 | bool "PMB" | 98 | bool "PMB" |
100 | depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785) | 99 | depends on MMU && EXPERIMENTAL && CPU_SH4A |
101 | select 32BIT | ||
102 | help | 100 | help |
103 | If you say Y here, physical addressing will be extended to | 101 | If you say Y here, physical addressing will be extended to |
104 | 32-bits through the SH-4A PMB. If this is not set, legacy | 102 | 32-bits through the SH-4A PMB. If this is not set, legacy |
@@ -106,9 +104,7 @@ config PMB | |||
106 | 104 | ||
107 | config PMB_FIXED | 105 | config PMB_FIXED |
108 | bool "fixed PMB" | 106 | bool "fixed PMB" |
109 | depends on MMU && EXPERIMENTAL && (CPU_SUBTYPE_SH7757 || \ | 107 | depends on MMU && EXPERIMENTAL && CPU_SH4A |
110 | CPU_SUBTYPE_SH7780 || \ | ||
111 | CPU_SUBTYPE_SH7785) | ||
112 | select 32BIT | 108 | select 32BIT |
113 | help | 109 | help |
114 | If this option is enabled, fixed PMB mappings are inherited | 110 | If this option is enabled, fixed PMB mappings are inherited |
@@ -258,6 +254,15 @@ endchoice | |||
258 | 254 | ||
259 | source "mm/Kconfig" | 255 | source "mm/Kconfig" |
260 | 256 | ||
257 | config SCHED_MC | ||
258 | bool "Multi-core scheduler support" | ||
259 | depends on SMP | ||
260 | default y | ||
261 | help | ||
262 | Multi-core scheduler support improves the CPU scheduler's decision | ||
263 | making when dealing with multi-core CPU chips at a cost of slightly | ||
264 | increased overhead in some places. If unsure say N here. | ||
265 | |||
261 | endmenu | 266 | endmenu |
262 | 267 | ||
263 | menu "Cache configuration" | 268 | menu "Cache configuration" |
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index 3759bf853293..8a70535fa7ce 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile | |||
@@ -33,8 +33,7 @@ obj-y += $(tlb-y) | |||
33 | endif | 33 | endif |
34 | 34 | ||
35 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 35 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
36 | obj-$(CONFIG_PMB) += pmb.o | 36 | obj-$(CONFIG_PMB_ENABLE) += pmb.o |
37 | obj-$(CONFIG_PMB_FIXED) += pmb-fixed.o | ||
38 | obj-$(CONFIG_NUMA) += numa.o | 37 | obj-$(CONFIG_NUMA) += numa.o |
39 | 38 | ||
40 | # Special flags for fault_64.o. This puts restrictions on the number of | 39 | # Special flags for fault_64.o. This puts restrictions on the number of |
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c index b7f235c74d66..f36a08bf3d5c 100644 --- a/arch/sh/mm/cache-sh4.c +++ b/arch/sh/mm/cache-sh4.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * arch/sh/mm/cache-sh4.c | 2 | * arch/sh/mm/cache-sh4.c |
3 | * | 3 | * |
4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka | 4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka |
5 | * Copyright (C) 2001 - 2007 Paul Mundt | 5 | * Copyright (C) 2001 - 2009 Paul Mundt |
6 | * Copyright (C) 2003 Richard Curnow | 6 | * Copyright (C) 2003 Richard Curnow |
7 | * Copyright (c) 2007 STMicroelectronics (R&D) Ltd. | 7 | * Copyright (c) 2007 STMicroelectronics (R&D) Ltd. |
8 | * | 8 | * |
@@ -15,6 +15,8 @@ | |||
15 | #include <linux/io.h> | 15 | #include <linux/io.h> |
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/highmem.h> | ||
19 | #include <asm/pgtable.h> | ||
18 | #include <asm/mmu_context.h> | 20 | #include <asm/mmu_context.h> |
19 | #include <asm/cacheflush.h> | 21 | #include <asm/cacheflush.h> |
20 | 22 | ||
@@ -23,21 +25,12 @@ | |||
23 | * flushing. Anything exceeding this will simply flush the dcache in its | 25 | * flushing. Anything exceeding this will simply flush the dcache in its |
24 | * entirety. | 26 | * entirety. |
25 | */ | 27 | */ |
26 | #define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */ | ||
27 | #define MAX_ICACHE_PAGES 32 | 28 | #define MAX_ICACHE_PAGES 32 |
28 | 29 | ||
29 | static void __flush_cache_one(unsigned long addr, unsigned long phys, | 30 | static void __flush_cache_one(unsigned long addr, unsigned long phys, |
30 | unsigned long exec_offset); | 31 | unsigned long exec_offset); |
31 | 32 | ||
32 | /* | 33 | /* |
33 | * This is initialised here to ensure that it is not placed in the BSS. If | ||
34 | * that were to happen, note that cache_init gets called before the BSS is | ||
35 | * cleared, so this would get nulled out which would be hopeless. | ||
36 | */ | ||
37 | static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) = | ||
38 | (void (*)(unsigned long, unsigned long))0xdeadbeef; | ||
39 | |||
40 | /* | ||
41 | * Write back the range of D-cache, and purge the I-cache. | 34 | * Write back the range of D-cache, and purge the I-cache. |
42 | * | 35 | * |
43 | * Called from kernel/module.c:sys_init_module and routine for a.out format, | 36 | * Called from kernel/module.c:sys_init_module and routine for a.out format, |
@@ -97,15 +90,15 @@ static inline void flush_cache_one(unsigned long start, unsigned long phys) | |||
97 | unsigned long flags, exec_offset = 0; | 90 | unsigned long flags, exec_offset = 0; |
98 | 91 | ||
99 | /* | 92 | /* |
100 | * All types of SH-4 require PC to be in P2 to operate on the I-cache. | 93 | * All types of SH-4 require PC to be uncached to operate on the I-cache. |
101 | * Some types of SH-4 require PC to be in P2 to operate on the D-cache. | 94 | * Some types of SH-4 require PC to be uncached to operate on the D-cache. |
102 | */ | 95 | */ |
103 | if ((boot_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) || | 96 | if ((boot_cpu_data.flags & CPU_HAS_P2_FLUSH_BUG) || |
104 | (start < CACHE_OC_ADDRESS_ARRAY)) | 97 | (start < CACHE_OC_ADDRESS_ARRAY)) |
105 | exec_offset = 0x20000000; | 98 | exec_offset = cached_to_uncached; |
106 | 99 | ||
107 | local_irq_save(flags); | 100 | local_irq_save(flags); |
108 | __flush_cache_one(start | SH_CACHE_ASSOC, P1SEGADDR(phys), exec_offset); | 101 | __flush_cache_one(start, phys, exec_offset); |
109 | local_irq_restore(flags); | 102 | local_irq_restore(flags); |
110 | } | 103 | } |
111 | 104 | ||
@@ -124,7 +117,7 @@ static void sh4_flush_dcache_page(void *arg) | |||
124 | else | 117 | else |
125 | #endif | 118 | #endif |
126 | { | 119 | { |
127 | unsigned long phys = PHYSADDR(page_address(page)); | 120 | unsigned long phys = page_to_phys(page); |
128 | unsigned long addr = CACHE_OC_ADDRESS_ARRAY; | 121 | unsigned long addr = CACHE_OC_ADDRESS_ARRAY; |
129 | int i, n; | 122 | int i, n; |
130 | 123 | ||
@@ -159,10 +152,27 @@ static void __uses_jump_to_uncached flush_icache_all(void) | |||
159 | local_irq_restore(flags); | 152 | local_irq_restore(flags); |
160 | } | 153 | } |
161 | 154 | ||
162 | static inline void flush_dcache_all(void) | 155 | static void flush_dcache_all(void) |
163 | { | 156 | { |
164 | (*__flush_dcache_segment_fn)(0UL, boot_cpu_data.dcache.way_size); | 157 | unsigned long addr, end_addr, entry_offset; |
165 | wmb(); | 158 | |
159 | end_addr = CACHE_OC_ADDRESS_ARRAY + | ||
160 | (current_cpu_data.dcache.sets << | ||
161 | current_cpu_data.dcache.entry_shift) * | ||
162 | current_cpu_data.dcache.ways; | ||
163 | |||
164 | entry_offset = 1 << current_cpu_data.dcache.entry_shift; | ||
165 | |||
166 | for (addr = CACHE_OC_ADDRESS_ARRAY; addr < end_addr; ) { | ||
167 | __raw_writel(0, addr); addr += entry_offset; | ||
168 | __raw_writel(0, addr); addr += entry_offset; | ||
169 | __raw_writel(0, addr); addr += entry_offset; | ||
170 | __raw_writel(0, addr); addr += entry_offset; | ||
171 | __raw_writel(0, addr); addr += entry_offset; | ||
172 | __raw_writel(0, addr); addr += entry_offset; | ||
173 | __raw_writel(0, addr); addr += entry_offset; | ||
174 | __raw_writel(0, addr); addr += entry_offset; | ||
175 | } | ||
166 | } | 176 | } |
167 | 177 | ||
168 | static void sh4_flush_cache_all(void *unused) | 178 | static void sh4_flush_cache_all(void *unused) |
@@ -171,89 +181,13 @@ static void sh4_flush_cache_all(void *unused) | |||
171 | flush_icache_all(); | 181 | flush_icache_all(); |
172 | } | 182 | } |
173 | 183 | ||
174 | static void __flush_cache_mm(struct mm_struct *mm, unsigned long start, | ||
175 | unsigned long end) | ||
176 | { | ||
177 | unsigned long d = 0, p = start & PAGE_MASK; | ||
178 | unsigned long alias_mask = boot_cpu_data.dcache.alias_mask; | ||
179 | unsigned long n_aliases = boot_cpu_data.dcache.n_aliases; | ||
180 | unsigned long select_bit; | ||
181 | unsigned long all_aliases_mask; | ||
182 | unsigned long addr_offset; | ||
183 | pgd_t *dir; | ||
184 | pmd_t *pmd; | ||
185 | pud_t *pud; | ||
186 | pte_t *pte; | ||
187 | int i; | ||
188 | |||
189 | dir = pgd_offset(mm, p); | ||
190 | pud = pud_offset(dir, p); | ||
191 | pmd = pmd_offset(pud, p); | ||
192 | end = PAGE_ALIGN(end); | ||
193 | |||
194 | all_aliases_mask = (1 << n_aliases) - 1; | ||
195 | |||
196 | do { | ||
197 | if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) { | ||
198 | p &= PMD_MASK; | ||
199 | p += PMD_SIZE; | ||
200 | pmd++; | ||
201 | |||
202 | continue; | ||
203 | } | ||
204 | |||
205 | pte = pte_offset_kernel(pmd, p); | ||
206 | |||
207 | do { | ||
208 | unsigned long phys; | ||
209 | pte_t entry = *pte; | ||
210 | |||
211 | if (!(pte_val(entry) & _PAGE_PRESENT)) { | ||
212 | pte++; | ||
213 | p += PAGE_SIZE; | ||
214 | continue; | ||
215 | } | ||
216 | |||
217 | phys = pte_val(entry) & PTE_PHYS_MASK; | ||
218 | |||
219 | if ((p ^ phys) & alias_mask) { | ||
220 | d |= 1 << ((p & alias_mask) >> PAGE_SHIFT); | ||
221 | d |= 1 << ((phys & alias_mask) >> PAGE_SHIFT); | ||
222 | |||
223 | if (d == all_aliases_mask) | ||
224 | goto loop_exit; | ||
225 | } | ||
226 | |||
227 | pte++; | ||
228 | p += PAGE_SIZE; | ||
229 | } while (p < end && ((unsigned long)pte & ~PAGE_MASK)); | ||
230 | pmd++; | ||
231 | } while (p < end); | ||
232 | |||
233 | loop_exit: | ||
234 | addr_offset = 0; | ||
235 | select_bit = 1; | ||
236 | |||
237 | for (i = 0; i < n_aliases; i++) { | ||
238 | if (d & select_bit) { | ||
239 | (*__flush_dcache_segment_fn)(addr_offset, PAGE_SIZE); | ||
240 | wmb(); | ||
241 | } | ||
242 | |||
243 | select_bit <<= 1; | ||
244 | addr_offset += PAGE_SIZE; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | /* | 184 | /* |
249 | * Note : (RPC) since the caches are physically tagged, the only point | 185 | * Note : (RPC) since the caches are physically tagged, the only point |
250 | * of flush_cache_mm for SH-4 is to get rid of aliases from the | 186 | * of flush_cache_mm for SH-4 is to get rid of aliases from the |
251 | * D-cache. The assumption elsewhere, e.g. flush_cache_range, is that | 187 | * D-cache. The assumption elsewhere, e.g. flush_cache_range, is that |
252 | * lines can stay resident so long as the virtual address they were | 188 | * lines can stay resident so long as the virtual address they were |
253 | * accessed with (hence cache set) is in accord with the physical | 189 | * accessed with (hence cache set) is in accord with the physical |
254 | * address (i.e. tag). It's no different here. So I reckon we don't | 190 | * address (i.e. tag). It's no different here. |
255 | * need to flush the I-cache, since aliases don't matter for that. We | ||
256 | * should try that. | ||
257 | * | 191 | * |
258 | * Caller takes mm->mmap_sem. | 192 | * Caller takes mm->mmap_sem. |
259 | */ | 193 | */ |
@@ -264,33 +198,7 @@ static void sh4_flush_cache_mm(void *arg) | |||
264 | if (cpu_context(smp_processor_id(), mm) == NO_CONTEXT) | 198 | if (cpu_context(smp_processor_id(), mm) == NO_CONTEXT) |
265 | return; | 199 | return; |
266 | 200 | ||
267 | /* | 201 | flush_dcache_all(); |
268 | * If cache is only 4k-per-way, there are never any 'aliases'. Since | ||
269 | * the cache is physically tagged, the data can just be left in there. | ||
270 | */ | ||
271 | if (boot_cpu_data.dcache.n_aliases == 0) | ||
272 | return; | ||
273 | |||
274 | /* | ||
275 | * Don't bother groveling around the dcache for the VMA ranges | ||
276 | * if there are too many PTEs to make it worthwhile. | ||
277 | */ | ||
278 | if (mm->nr_ptes >= MAX_DCACHE_PAGES) | ||
279 | flush_dcache_all(); | ||
280 | else { | ||
281 | struct vm_area_struct *vma; | ||
282 | |||
283 | /* | ||
284 | * In this case there are reasonably sized ranges to flush, | ||
285 | * iterate through the VMA list and take care of any aliases. | ||
286 | */ | ||
287 | for (vma = mm->mmap; vma; vma = vma->vm_next) | ||
288 | __flush_cache_mm(mm, vma->vm_start, vma->vm_end); | ||
289 | } | ||
290 | |||
291 | /* Only touch the icache if one of the VMAs has VM_EXEC set. */ | ||
292 | if (mm->exec_vm) | ||
293 | flush_icache_all(); | ||
294 | } | 202 | } |
295 | 203 | ||
296 | /* | 204 | /* |
@@ -303,44 +211,63 @@ static void sh4_flush_cache_page(void *args) | |||
303 | { | 211 | { |
304 | struct flusher_data *data = args; | 212 | struct flusher_data *data = args; |
305 | struct vm_area_struct *vma; | 213 | struct vm_area_struct *vma; |
214 | struct page *page; | ||
306 | unsigned long address, pfn, phys; | 215 | unsigned long address, pfn, phys; |
307 | unsigned int alias_mask; | 216 | int map_coherent = 0; |
217 | pgd_t *pgd; | ||
218 | pud_t *pud; | ||
219 | pmd_t *pmd; | ||
220 | pte_t *pte; | ||
221 | void *vaddr; | ||
308 | 222 | ||
309 | vma = data->vma; | 223 | vma = data->vma; |
310 | address = data->addr1; | 224 | address = data->addr1 & PAGE_MASK; |
311 | pfn = data->addr2; | 225 | pfn = data->addr2; |
312 | phys = pfn << PAGE_SHIFT; | 226 | phys = pfn << PAGE_SHIFT; |
227 | page = pfn_to_page(pfn); | ||
313 | 228 | ||
314 | if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT) | 229 | if (cpu_context(smp_processor_id(), vma->vm_mm) == NO_CONTEXT) |
315 | return; | 230 | return; |
316 | 231 | ||
317 | alias_mask = boot_cpu_data.dcache.alias_mask; | 232 | pgd = pgd_offset(vma->vm_mm, address); |
318 | 233 | pud = pud_offset(pgd, address); | |
319 | /* We only need to flush D-cache when we have alias */ | 234 | pmd = pmd_offset(pud, address); |
320 | if ((address^phys) & alias_mask) { | 235 | pte = pte_offset_kernel(pmd, address); |
321 | /* Loop 4K of the D-cache */ | 236 | |
322 | flush_cache_one( | 237 | /* If the page isn't present, there is nothing to do here. */ |
323 | CACHE_OC_ADDRESS_ARRAY | (address & alias_mask), | 238 | if (!(pte_val(*pte) & _PAGE_PRESENT)) |
324 | phys); | 239 | return; |
325 | /* Loop another 4K of the D-cache */ | ||
326 | flush_cache_one( | ||
327 | CACHE_OC_ADDRESS_ARRAY | (phys & alias_mask), | ||
328 | phys); | ||
329 | } | ||
330 | 240 | ||
331 | alias_mask = boot_cpu_data.icache.alias_mask; | 241 | if ((vma->vm_mm == current->active_mm)) |
332 | if (vma->vm_flags & VM_EXEC) { | 242 | vaddr = NULL; |
243 | else { | ||
333 | /* | 244 | /* |
334 | * Evict entries from the portion of the cache from which code | 245 | * Use kmap_coherent or kmap_atomic to do flushes for |
335 | * may have been executed at this address (virtual). There's | 246 | * another ASID than the current one. |
336 | * no need to evict from the portion corresponding to the | ||
337 | * physical address as for the D-cache, because we know the | ||
338 | * kernel has never executed the code through its identity | ||
339 | * translation. | ||
340 | */ | 247 | */ |
341 | flush_cache_one( | 248 | map_coherent = (current_cpu_data.dcache.n_aliases && |
342 | CACHE_IC_ADDRESS_ARRAY | (address & alias_mask), | 249 | !test_bit(PG_dcache_dirty, &page->flags) && |
343 | phys); | 250 | page_mapped(page)); |
251 | if (map_coherent) | ||
252 | vaddr = kmap_coherent(page, address); | ||
253 | else | ||
254 | vaddr = kmap_atomic(page, KM_USER0); | ||
255 | |||
256 | address = (unsigned long)vaddr; | ||
257 | } | ||
258 | |||
259 | if (pages_do_alias(address, phys)) | ||
260 | flush_cache_one(CACHE_OC_ADDRESS_ARRAY | | ||
261 | (address & shm_align_mask), phys); | ||
262 | |||
263 | if (vma->vm_flags & VM_EXEC) | ||
264 | flush_icache_all(); | ||
265 | |||
266 | if (vaddr) { | ||
267 | if (map_coherent) | ||
268 | kunmap_coherent(vaddr); | ||
269 | else | ||
270 | kunmap_atomic(vaddr, KM_USER0); | ||
344 | } | 271 | } |
345 | } | 272 | } |
346 | 273 | ||
@@ -373,24 +300,10 @@ static void sh4_flush_cache_range(void *args) | |||
373 | if (boot_cpu_data.dcache.n_aliases == 0) | 300 | if (boot_cpu_data.dcache.n_aliases == 0) |
374 | return; | 301 | return; |
375 | 302 | ||
376 | /* | 303 | flush_dcache_all(); |
377 | * Don't bother with the lookup and alias check if we have a | ||
378 | * wide range to cover, just blow away the dcache in its | ||
379 | * entirety instead. -- PFM. | ||
380 | */ | ||
381 | if (((end - start) >> PAGE_SHIFT) >= MAX_DCACHE_PAGES) | ||
382 | flush_dcache_all(); | ||
383 | else | ||
384 | __flush_cache_mm(vma->vm_mm, start, end); | ||
385 | 304 | ||
386 | if (vma->vm_flags & VM_EXEC) { | 305 | if (vma->vm_flags & VM_EXEC) |
387 | /* | ||
388 | * TODO: Is this required??? Need to look at how I-cache | ||
389 | * coherency is assured when new programs are loaded to see if | ||
390 | * this matters. | ||
391 | */ | ||
392 | flush_icache_all(); | 306 | flush_icache_all(); |
393 | } | ||
394 | } | 307 | } |
395 | 308 | ||
396 | /** | 309 | /** |
@@ -464,245 +377,6 @@ static void __flush_cache_one(unsigned long addr, unsigned long phys, | |||
464 | } while (--way_count != 0); | 377 | } while (--way_count != 0); |
465 | } | 378 | } |
466 | 379 | ||
467 | /* | ||
468 | * Break the 1, 2 and 4 way variants of this out into separate functions to | ||
469 | * avoid nearly all the overhead of having the conditional stuff in the function | ||
470 | * bodies (+ the 1 and 2 way cases avoid saving any registers too). | ||
471 | * | ||
472 | * We want to eliminate unnecessary bus transactions, so this code uses | ||
473 | * a non-obvious technique. | ||
474 | * | ||
475 | * Loop over a cache way sized block of, one cache line at a time. For each | ||
476 | * line, use movca.a to cause the current cache line contents to be written | ||
477 | * back, but without reading anything from main memory. However this has the | ||
478 | * side effect that the cache is now caching that memory location. So follow | ||
479 | * this with a cache invalidate to mark the cache line invalid. And do all | ||
480 | * this with interrupts disabled, to avoid the cache line being accidently | ||
481 | * evicted while it is holding garbage. | ||
482 | * | ||
483 | * This also breaks in a number of circumstances: | ||
484 | * - if there are modifications to the region of memory just above | ||
485 | * empty_zero_page (for example because a breakpoint has been placed | ||
486 | * there), then these can be lost. | ||
487 | * | ||
488 | * This is because the the memory address which the cache temporarily | ||
489 | * caches in the above description is empty_zero_page. So the | ||
490 | * movca.l hits the cache (it is assumed that it misses, or at least | ||
491 | * isn't dirty), modifies the line and then invalidates it, losing the | ||
492 | * required change. | ||
493 | * | ||
494 | * - If caches are disabled or configured in write-through mode, then | ||
495 | * the movca.l writes garbage directly into memory. | ||
496 | */ | ||
497 | static void __flush_dcache_segment_writethrough(unsigned long start, | ||
498 | unsigned long extent_per_way) | ||
499 | { | ||
500 | unsigned long addr; | ||
501 | int i; | ||
502 | |||
503 | addr = CACHE_OC_ADDRESS_ARRAY | (start & cpu_data->dcache.entry_mask); | ||
504 | |||
505 | while (extent_per_way) { | ||
506 | for (i = 0; i < cpu_data->dcache.ways; i++) | ||
507 | __raw_writel(0, addr + cpu_data->dcache.way_incr * i); | ||
508 | |||
509 | addr += cpu_data->dcache.linesz; | ||
510 | extent_per_way -= cpu_data->dcache.linesz; | ||
511 | } | ||
512 | } | ||
513 | |||
514 | static void __flush_dcache_segment_1way(unsigned long start, | ||
515 | unsigned long extent_per_way) | ||
516 | { | ||
517 | unsigned long orig_sr, sr_with_bl; | ||
518 | unsigned long base_addr; | ||
519 | unsigned long way_incr, linesz, way_size; | ||
520 | struct cache_info *dcache; | ||
521 | register unsigned long a0, a0e; | ||
522 | |||
523 | asm volatile("stc sr, %0" : "=r" (orig_sr)); | ||
524 | sr_with_bl = orig_sr | (1<<28); | ||
525 | base_addr = ((unsigned long)&empty_zero_page[0]); | ||
526 | |||
527 | /* | ||
528 | * The previous code aligned base_addr to 16k, i.e. the way_size of all | ||
529 | * existing SH-4 D-caches. Whilst I don't see a need to have this | ||
530 | * aligned to any better than the cache line size (which it will be | ||
531 | * anyway by construction), let's align it to at least the way_size of | ||
532 | * any existing or conceivable SH-4 D-cache. -- RPC | ||
533 | */ | ||
534 | base_addr = ((base_addr >> 16) << 16); | ||
535 | base_addr |= start; | ||
536 | |||
537 | dcache = &boot_cpu_data.dcache; | ||
538 | linesz = dcache->linesz; | ||
539 | way_incr = dcache->way_incr; | ||
540 | way_size = dcache->way_size; | ||
541 | |||
542 | a0 = base_addr; | ||
543 | a0e = base_addr + extent_per_way; | ||
544 | do { | ||
545 | asm volatile("ldc %0, sr" : : "r" (sr_with_bl)); | ||
546 | asm volatile("movca.l r0, @%0\n\t" | ||
547 | "ocbi @%0" : : "r" (a0)); | ||
548 | a0 += linesz; | ||
549 | asm volatile("movca.l r0, @%0\n\t" | ||
550 | "ocbi @%0" : : "r" (a0)); | ||
551 | a0 += linesz; | ||
552 | asm volatile("movca.l r0, @%0\n\t" | ||
553 | "ocbi @%0" : : "r" (a0)); | ||
554 | a0 += linesz; | ||
555 | asm volatile("movca.l r0, @%0\n\t" | ||
556 | "ocbi @%0" : : "r" (a0)); | ||
557 | asm volatile("ldc %0, sr" : : "r" (orig_sr)); | ||
558 | a0 += linesz; | ||
559 | } while (a0 < a0e); | ||
560 | } | ||
561 | |||
562 | static void __flush_dcache_segment_2way(unsigned long start, | ||
563 | unsigned long extent_per_way) | ||
564 | { | ||
565 | unsigned long orig_sr, sr_with_bl; | ||
566 | unsigned long base_addr; | ||
567 | unsigned long way_incr, linesz, way_size; | ||
568 | struct cache_info *dcache; | ||
569 | register unsigned long a0, a1, a0e; | ||
570 | |||
571 | asm volatile("stc sr, %0" : "=r" (orig_sr)); | ||
572 | sr_with_bl = orig_sr | (1<<28); | ||
573 | base_addr = ((unsigned long)&empty_zero_page[0]); | ||
574 | |||
575 | /* See comment under 1-way above */ | ||
576 | base_addr = ((base_addr >> 16) << 16); | ||
577 | base_addr |= start; | ||
578 | |||
579 | dcache = &boot_cpu_data.dcache; | ||
580 | linesz = dcache->linesz; | ||
581 | way_incr = dcache->way_incr; | ||
582 | way_size = dcache->way_size; | ||
583 | |||
584 | a0 = base_addr; | ||
585 | a1 = a0 + way_incr; | ||
586 | a0e = base_addr + extent_per_way; | ||
587 | do { | ||
588 | asm volatile("ldc %0, sr" : : "r" (sr_with_bl)); | ||
589 | asm volatile("movca.l r0, @%0\n\t" | ||
590 | "movca.l r0, @%1\n\t" | ||
591 | "ocbi @%0\n\t" | ||
592 | "ocbi @%1" : : | ||
593 | "r" (a0), "r" (a1)); | ||
594 | a0 += linesz; | ||
595 | a1 += linesz; | ||
596 | asm volatile("movca.l r0, @%0\n\t" | ||
597 | "movca.l r0, @%1\n\t" | ||
598 | "ocbi @%0\n\t" | ||
599 | "ocbi @%1" : : | ||
600 | "r" (a0), "r" (a1)); | ||
601 | a0 += linesz; | ||
602 | a1 += linesz; | ||
603 | asm volatile("movca.l r0, @%0\n\t" | ||
604 | "movca.l r0, @%1\n\t" | ||
605 | "ocbi @%0\n\t" | ||
606 | "ocbi @%1" : : | ||
607 | "r" (a0), "r" (a1)); | ||
608 | a0 += linesz; | ||
609 | a1 += linesz; | ||
610 | asm volatile("movca.l r0, @%0\n\t" | ||
611 | "movca.l r0, @%1\n\t" | ||
612 | "ocbi @%0\n\t" | ||
613 | "ocbi @%1" : : | ||
614 | "r" (a0), "r" (a1)); | ||
615 | asm volatile("ldc %0, sr" : : "r" (orig_sr)); | ||
616 | a0 += linesz; | ||
617 | a1 += linesz; | ||
618 | } while (a0 < a0e); | ||
619 | } | ||
620 | |||
621 | static void __flush_dcache_segment_4way(unsigned long start, | ||
622 | unsigned long extent_per_way) | ||
623 | { | ||
624 | unsigned long orig_sr, sr_with_bl; | ||
625 | unsigned long base_addr; | ||
626 | unsigned long way_incr, linesz, way_size; | ||
627 | struct cache_info *dcache; | ||
628 | register unsigned long a0, a1, a2, a3, a0e; | ||
629 | |||
630 | asm volatile("stc sr, %0" : "=r" (orig_sr)); | ||
631 | sr_with_bl = orig_sr | (1<<28); | ||
632 | base_addr = ((unsigned long)&empty_zero_page[0]); | ||
633 | |||
634 | /* See comment under 1-way above */ | ||
635 | base_addr = ((base_addr >> 16) << 16); | ||
636 | base_addr |= start; | ||
637 | |||
638 | dcache = &boot_cpu_data.dcache; | ||
639 | linesz = dcache->linesz; | ||
640 | way_incr = dcache->way_incr; | ||
641 | way_size = dcache->way_size; | ||
642 | |||
643 | a0 = base_addr; | ||
644 | a1 = a0 + way_incr; | ||
645 | a2 = a1 + way_incr; | ||
646 | a3 = a2 + way_incr; | ||
647 | a0e = base_addr + extent_per_way; | ||
648 | do { | ||
649 | asm volatile("ldc %0, sr" : : "r" (sr_with_bl)); | ||
650 | asm volatile("movca.l r0, @%0\n\t" | ||
651 | "movca.l r0, @%1\n\t" | ||
652 | "movca.l r0, @%2\n\t" | ||
653 | "movca.l r0, @%3\n\t" | ||
654 | "ocbi @%0\n\t" | ||
655 | "ocbi @%1\n\t" | ||
656 | "ocbi @%2\n\t" | ||
657 | "ocbi @%3\n\t" : : | ||
658 | "r" (a0), "r" (a1), "r" (a2), "r" (a3)); | ||
659 | a0 += linesz; | ||
660 | a1 += linesz; | ||
661 | a2 += linesz; | ||
662 | a3 += linesz; | ||
663 | asm volatile("movca.l r0, @%0\n\t" | ||
664 | "movca.l r0, @%1\n\t" | ||
665 | "movca.l r0, @%2\n\t" | ||
666 | "movca.l r0, @%3\n\t" | ||
667 | "ocbi @%0\n\t" | ||
668 | "ocbi @%1\n\t" | ||
669 | "ocbi @%2\n\t" | ||
670 | "ocbi @%3\n\t" : : | ||
671 | "r" (a0), "r" (a1), "r" (a2), "r" (a3)); | ||
672 | a0 += linesz; | ||
673 | a1 += linesz; | ||
674 | a2 += linesz; | ||
675 | a3 += linesz; | ||
676 | asm volatile("movca.l r0, @%0\n\t" | ||
677 | "movca.l r0, @%1\n\t" | ||
678 | "movca.l r0, @%2\n\t" | ||
679 | "movca.l r0, @%3\n\t" | ||
680 | "ocbi @%0\n\t" | ||
681 | "ocbi @%1\n\t" | ||
682 | "ocbi @%2\n\t" | ||
683 | "ocbi @%3\n\t" : : | ||
684 | "r" (a0), "r" (a1), "r" (a2), "r" (a3)); | ||
685 | a0 += linesz; | ||
686 | a1 += linesz; | ||
687 | a2 += linesz; | ||
688 | a3 += linesz; | ||
689 | asm volatile("movca.l r0, @%0\n\t" | ||
690 | "movca.l r0, @%1\n\t" | ||
691 | "movca.l r0, @%2\n\t" | ||
692 | "movca.l r0, @%3\n\t" | ||
693 | "ocbi @%0\n\t" | ||
694 | "ocbi @%1\n\t" | ||
695 | "ocbi @%2\n\t" | ||
696 | "ocbi @%3\n\t" : : | ||
697 | "r" (a0), "r" (a1), "r" (a2), "r" (a3)); | ||
698 | asm volatile("ldc %0, sr" : : "r" (orig_sr)); | ||
699 | a0 += linesz; | ||
700 | a1 += linesz; | ||
701 | a2 += linesz; | ||
702 | a3 += linesz; | ||
703 | } while (a0 < a0e); | ||
704 | } | ||
705 | |||
706 | extern void __weak sh4__flush_region_init(void); | 380 | extern void __weak sh4__flush_region_init(void); |
707 | 381 | ||
708 | /* | 382 | /* |
@@ -710,32 +384,11 @@ extern void __weak sh4__flush_region_init(void); | |||
710 | */ | 384 | */ |
711 | void __init sh4_cache_init(void) | 385 | void __init sh4_cache_init(void) |
712 | { | 386 | { |
713 | unsigned int wt_enabled = !!(__raw_readl(CCR) & CCR_CACHE_WT); | ||
714 | |||
715 | printk("PVR=%08x CVR=%08x PRR=%08x\n", | 387 | printk("PVR=%08x CVR=%08x PRR=%08x\n", |
716 | ctrl_inl(CCN_PVR), | 388 | ctrl_inl(CCN_PVR), |
717 | ctrl_inl(CCN_CVR), | 389 | ctrl_inl(CCN_CVR), |
718 | ctrl_inl(CCN_PRR)); | 390 | ctrl_inl(CCN_PRR)); |
719 | 391 | ||
720 | if (wt_enabled) | ||
721 | __flush_dcache_segment_fn = __flush_dcache_segment_writethrough; | ||
722 | else { | ||
723 | switch (boot_cpu_data.dcache.ways) { | ||
724 | case 1: | ||
725 | __flush_dcache_segment_fn = __flush_dcache_segment_1way; | ||
726 | break; | ||
727 | case 2: | ||
728 | __flush_dcache_segment_fn = __flush_dcache_segment_2way; | ||
729 | break; | ||
730 | case 4: | ||
731 | __flush_dcache_segment_fn = __flush_dcache_segment_4way; | ||
732 | break; | ||
733 | default: | ||
734 | panic("unknown number of cache ways\n"); | ||
735 | break; | ||
736 | } | ||
737 | } | ||
738 | |||
739 | local_flush_icache_range = sh4_flush_icache_range; | 392 | local_flush_icache_range = sh4_flush_icache_range; |
740 | local_flush_dcache_page = sh4_flush_dcache_page; | 393 | local_flush_dcache_page = sh4_flush_dcache_page; |
741 | local_flush_cache_all = sh4_flush_cache_all; | 394 | local_flush_cache_all = sh4_flush_cache_all; |
diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 467ff8e260f7..eb4cc4ec7952 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c | |||
@@ -563,7 +563,7 @@ static void sh5_flush_cache_page(void *args) | |||
563 | 563 | ||
564 | static void sh5_flush_dcache_page(void *page) | 564 | static void sh5_flush_dcache_page(void *page) |
565 | { | 565 | { |
566 | sh64_dcache_purge_phy_page(page_to_phys(page)); | 566 | sh64_dcache_purge_phy_page(page_to_phys((struct page *)page)); |
567 | wmb(); | 567 | wmb(); |
568 | } | 568 | } |
569 | 569 | ||
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 2601935eb589..f527fb70fce6 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c | |||
@@ -141,7 +141,7 @@ static void sh7705_flush_dcache_page(void *arg) | |||
141 | if (mapping && !mapping_mapped(mapping)) | 141 | if (mapping && !mapping_mapped(mapping)) |
142 | set_bit(PG_dcache_dirty, &page->flags); | 142 | set_bit(PG_dcache_dirty, &page->flags); |
143 | else | 143 | else |
144 | __flush_dcache_page(PHYSADDR(page_address(page))); | 144 | __flush_dcache_page(__pa(page_address(page))); |
145 | } | 145 | } |
146 | 146 | ||
147 | static void __uses_jump_to_uncached sh7705_flush_cache_all(void *args) | 147 | static void __uses_jump_to_uncached sh7705_flush_cache_all(void *args) |
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index a2dc7f9ecc51..e9415d3ea94a 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c | |||
@@ -27,8 +27,11 @@ void (*local_flush_icache_page)(void *args) = cache_noop; | |||
27 | void (*local_flush_cache_sigtramp)(void *args) = cache_noop; | 27 | void (*local_flush_cache_sigtramp)(void *args) = cache_noop; |
28 | 28 | ||
29 | void (*__flush_wback_region)(void *start, int size); | 29 | void (*__flush_wback_region)(void *start, int size); |
30 | EXPORT_SYMBOL(__flush_wback_region); | ||
30 | void (*__flush_purge_region)(void *start, int size); | 31 | void (*__flush_purge_region)(void *start, int size); |
32 | EXPORT_SYMBOL(__flush_purge_region); | ||
31 | void (*__flush_invalidate_region)(void *start, int size); | 33 | void (*__flush_invalidate_region)(void *start, int size); |
34 | EXPORT_SYMBOL(__flush_invalidate_region); | ||
32 | 35 | ||
33 | static inline void noop__flush_region(void *start, int size) | 36 | static inline void noop__flush_region(void *start, int size) |
34 | { | 37 | { |
@@ -161,14 +164,21 @@ void flush_cache_all(void) | |||
161 | { | 164 | { |
162 | cacheop_on_each_cpu(local_flush_cache_all, NULL, 1); | 165 | cacheop_on_each_cpu(local_flush_cache_all, NULL, 1); |
163 | } | 166 | } |
167 | EXPORT_SYMBOL(flush_cache_all); | ||
164 | 168 | ||
165 | void flush_cache_mm(struct mm_struct *mm) | 169 | void flush_cache_mm(struct mm_struct *mm) |
166 | { | 170 | { |
171 | if (boot_cpu_data.dcache.n_aliases == 0) | ||
172 | return; | ||
173 | |||
167 | cacheop_on_each_cpu(local_flush_cache_mm, mm, 1); | 174 | cacheop_on_each_cpu(local_flush_cache_mm, mm, 1); |
168 | } | 175 | } |
169 | 176 | ||
170 | void flush_cache_dup_mm(struct mm_struct *mm) | 177 | void flush_cache_dup_mm(struct mm_struct *mm) |
171 | { | 178 | { |
179 | if (boot_cpu_data.dcache.n_aliases == 0) | ||
180 | return; | ||
181 | |||
172 | cacheop_on_each_cpu(local_flush_cache_dup_mm, mm, 1); | 182 | cacheop_on_each_cpu(local_flush_cache_dup_mm, mm, 1); |
173 | } | 183 | } |
174 | 184 | ||
@@ -195,11 +205,13 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, | |||
195 | 205 | ||
196 | cacheop_on_each_cpu(local_flush_cache_range, (void *)&data, 1); | 206 | cacheop_on_each_cpu(local_flush_cache_range, (void *)&data, 1); |
197 | } | 207 | } |
208 | EXPORT_SYMBOL(flush_cache_range); | ||
198 | 209 | ||
199 | void flush_dcache_page(struct page *page) | 210 | void flush_dcache_page(struct page *page) |
200 | { | 211 | { |
201 | cacheop_on_each_cpu(local_flush_dcache_page, page, 1); | 212 | cacheop_on_each_cpu(local_flush_dcache_page, page, 1); |
202 | } | 213 | } |
214 | EXPORT_SYMBOL(flush_dcache_page); | ||
203 | 215 | ||
204 | void flush_icache_range(unsigned long start, unsigned long end) | 216 | void flush_icache_range(unsigned long start, unsigned long end) |
205 | { | 217 | { |
@@ -265,7 +277,11 @@ static void __init emit_cache_params(void) | |||
265 | 277 | ||
266 | void __init cpu_cache_init(void) | 278 | void __init cpu_cache_init(void) |
267 | { | 279 | { |
268 | unsigned int cache_disabled = !(__raw_readl(CCR) & CCR_CACHE_ENABLE); | 280 | unsigned int cache_disabled = 0; |
281 | |||
282 | #ifdef CCR | ||
283 | cache_disabled = !(__raw_readl(CCR) & CCR_CACHE_ENABLE); | ||
284 | #endif | ||
269 | 285 | ||
270 | compute_alias(&boot_cpu_data.icache); | 286 | compute_alias(&boot_cpu_data.icache); |
271 | compute_alias(&boot_cpu_data.dcache); | 287 | compute_alias(&boot_cpu_data.dcache); |
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index e098ec158ddb..902967e3f841 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c | |||
@@ -15,11 +15,15 @@ | |||
15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
16 | #include <linux/dma-debug.h> | 16 | #include <linux/dma-debug.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/module.h> | ||
18 | #include <asm/cacheflush.h> | 19 | #include <asm/cacheflush.h> |
19 | #include <asm/addrspace.h> | 20 | #include <asm/addrspace.h> |
20 | 21 | ||
21 | #define PREALLOC_DMA_DEBUG_ENTRIES 4096 | 22 | #define PREALLOC_DMA_DEBUG_ENTRIES 4096 |
22 | 23 | ||
24 | struct dma_map_ops *dma_ops; | ||
25 | EXPORT_SYMBOL(dma_ops); | ||
26 | |||
23 | static int __init dma_init(void) | 27 | static int __init dma_init(void) |
24 | { | 28 | { |
25 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); | 29 | dma_debug_init(PREALLOC_DMA_DEBUG_ENTRIES); |
@@ -27,15 +31,12 @@ static int __init dma_init(void) | |||
27 | } | 31 | } |
28 | fs_initcall(dma_init); | 32 | fs_initcall(dma_init); |
29 | 33 | ||
30 | void *dma_alloc_coherent(struct device *dev, size_t size, | 34 | void *dma_generic_alloc_coherent(struct device *dev, size_t size, |
31 | dma_addr_t *dma_handle, gfp_t gfp) | 35 | dma_addr_t *dma_handle, gfp_t gfp) |
32 | { | 36 | { |
33 | void *ret, *ret_nocache; | 37 | void *ret, *ret_nocache; |
34 | int order = get_order(size); | 38 | int order = get_order(size); |
35 | 39 | ||
36 | if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) | ||
37 | return ret; | ||
38 | |||
39 | ret = (void *)__get_free_pages(gfp, order); | 40 | ret = (void *)__get_free_pages(gfp, order); |
40 | if (!ret) | 41 | if (!ret) |
41 | return NULL; | 42 | return NULL; |
@@ -57,35 +58,26 @@ void *dma_alloc_coherent(struct device *dev, size_t size, | |||
57 | 58 | ||
58 | *dma_handle = virt_to_phys(ret); | 59 | *dma_handle = virt_to_phys(ret); |
59 | 60 | ||
60 | debug_dma_alloc_coherent(dev, size, *dma_handle, ret_nocache); | ||
61 | |||
62 | return ret_nocache; | 61 | return ret_nocache; |
63 | } | 62 | } |
64 | EXPORT_SYMBOL(dma_alloc_coherent); | ||
65 | 63 | ||
66 | void dma_free_coherent(struct device *dev, size_t size, | 64 | void dma_generic_free_coherent(struct device *dev, size_t size, |
67 | void *vaddr, dma_addr_t dma_handle) | 65 | void *vaddr, dma_addr_t dma_handle) |
68 | { | 66 | { |
69 | int order = get_order(size); | 67 | int order = get_order(size); |
70 | unsigned long pfn = dma_handle >> PAGE_SHIFT; | 68 | unsigned long pfn = dma_handle >> PAGE_SHIFT; |
71 | int k; | 69 | int k; |
72 | 70 | ||
73 | WARN_ON(irqs_disabled()); /* for portability */ | ||
74 | |||
75 | if (dma_release_from_coherent(dev, order, vaddr)) | ||
76 | return; | ||
77 | |||
78 | debug_dma_free_coherent(dev, size, vaddr, dma_handle); | ||
79 | for (k = 0; k < (1 << order); k++) | 71 | for (k = 0; k < (1 << order); k++) |
80 | __free_pages(pfn_to_page(pfn + k), 0); | 72 | __free_pages(pfn_to_page(pfn + k), 0); |
73 | |||
81 | iounmap(vaddr); | 74 | iounmap(vaddr); |
82 | } | 75 | } |
83 | EXPORT_SYMBOL(dma_free_coherent); | ||
84 | 76 | ||
85 | void dma_cache_sync(struct device *dev, void *vaddr, size_t size, | 77 | void dma_cache_sync(struct device *dev, void *vaddr, size_t size, |
86 | enum dma_data_direction direction) | 78 | enum dma_data_direction direction) |
87 | { | 79 | { |
88 | #ifdef CONFIG_CPU_SH5 | 80 | #if defined(CONFIG_CPU_SH5) || defined(CONFIG_PMB) |
89 | void *p1addr = vaddr; | 81 | void *p1addr = vaddr; |
90 | #else | 82 | #else |
91 | void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr); | 83 | void *p1addr = (void*) P1SEGADDR((unsigned long)vaddr); |
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 8173e38afd38..432acd07e76a 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/pagemap.h> | 15 | #include <linux/pagemap.h> |
16 | #include <linux/percpu.h> | 16 | #include <linux/percpu.h> |
17 | #include <linux/io.h> | 17 | #include <linux/io.h> |
18 | #include <linux/dma-mapping.h> | ||
18 | #include <asm/mmu_context.h> | 19 | #include <asm/mmu_context.h> |
19 | #include <asm/tlb.h> | 20 | #include <asm/tlb.h> |
20 | #include <asm/cacheflush.h> | 21 | #include <asm/cacheflush.h> |
@@ -186,11 +187,21 @@ void __init paging_init(void) | |||
186 | set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start)); | 187 | set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start)); |
187 | } | 188 | } |
188 | 189 | ||
190 | /* | ||
191 | * Early initialization for any I/O MMUs we might have. | ||
192 | */ | ||
193 | static void __init iommu_init(void) | ||
194 | { | ||
195 | no_iommu_init(); | ||
196 | } | ||
197 | |||
189 | void __init mem_init(void) | 198 | void __init mem_init(void) |
190 | { | 199 | { |
191 | int codesize, datasize, initsize; | 200 | int codesize, datasize, initsize; |
192 | int nid; | 201 | int nid; |
193 | 202 | ||
203 | iommu_init(); | ||
204 | |||
194 | num_physpages = 0; | 205 | num_physpages = 0; |
195 | high_memory = NULL; | 206 | high_memory = NULL; |
196 | 207 | ||
@@ -323,4 +334,12 @@ int memory_add_physaddr_to_nid(u64 addr) | |||
323 | } | 334 | } |
324 | EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); | 335 | EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); |
325 | #endif | 336 | #endif |
337 | |||
326 | #endif /* CONFIG_MEMORY_HOTPLUG */ | 338 | #endif /* CONFIG_MEMORY_HOTPLUG */ |
339 | |||
340 | #ifdef CONFIG_PMB | ||
341 | int __in_29bit_mode(void) | ||
342 | { | ||
343 | return !(ctrl_inl(PMB_PASCR) & PASCR_SE); | ||
344 | } | ||
345 | #endif /* CONFIG_PMB */ | ||
diff --git a/arch/sh/mm/kmap.c b/arch/sh/mm/kmap.c index 16e01b5fed04..15d74ea42094 100644 --- a/arch/sh/mm/kmap.c +++ b/arch/sh/mm/kmap.c | |||
@@ -39,7 +39,9 @@ void *kmap_coherent(struct page *page, unsigned long addr) | |||
39 | pagefault_disable(); | 39 | pagefault_disable(); |
40 | 40 | ||
41 | idx = FIX_CMAP_END - | 41 | idx = FIX_CMAP_END - |
42 | ((addr & current_cpu_data.dcache.alias_mask) >> PAGE_SHIFT); | 42 | (((addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1)) + |
43 | (FIX_N_COLOURS * smp_processor_id())); | ||
44 | |||
43 | vaddr = __fix_to_virt(idx); | 45 | vaddr = __fix_to_virt(idx); |
44 | 46 | ||
45 | BUG_ON(!pte_none(*(kmap_coherent_pte - idx))); | 47 | BUG_ON(!pte_none(*(kmap_coherent_pte - idx))); |
diff --git a/arch/sh/mm/mmap.c b/arch/sh/mm/mmap.c index d2984fa42d3d..afeb710ec5c3 100644 --- a/arch/sh/mm/mmap.c +++ b/arch/sh/mm/mmap.c | |||
@@ -54,7 +54,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, | |||
54 | /* We do not accept a shared mapping if it would violate | 54 | /* We do not accept a shared mapping if it would violate |
55 | * cache aliasing constraints. | 55 | * cache aliasing constraints. |
56 | */ | 56 | */ |
57 | if ((flags & MAP_SHARED) && (addr & shm_align_mask)) | 57 | if ((flags & MAP_SHARED) && |
58 | ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) | ||
58 | return -EINVAL; | 59 | return -EINVAL; |
59 | return addr; | 60 | return addr; |
60 | } | 61 | } |
diff --git a/arch/sh/mm/numa.c b/arch/sh/mm/numa.c index 9b784fdb947c..6c524446c0f6 100644 --- a/arch/sh/mm/numa.c +++ b/arch/sh/mm/numa.c | |||
@@ -60,7 +60,7 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end) | |||
60 | unsigned long bootmem_paddr; | 60 | unsigned long bootmem_paddr; |
61 | 61 | ||
62 | /* Don't allow bogus node assignment */ | 62 | /* Don't allow bogus node assignment */ |
63 | BUG_ON(nid > MAX_NUMNODES || nid == 0); | 63 | BUG_ON(nid > MAX_NUMNODES || nid <= 0); |
64 | 64 | ||
65 | start_pfn = start >> PAGE_SHIFT; | 65 | start_pfn = start >> PAGE_SHIFT; |
66 | end_pfn = end >> PAGE_SHIFT; | 66 | end_pfn = end >> PAGE_SHIFT; |
diff --git a/arch/sh/mm/pmb-fixed.c b/arch/sh/mm/pmb-fixed.c deleted file mode 100644 index 43c8eac4d8a1..000000000000 --- a/arch/sh/mm/pmb-fixed.c +++ /dev/null | |||
@@ -1,45 +0,0 @@ | |||
1 | /* | ||
2 | * arch/sh/mm/fixed_pmb.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file "COPYING" in the main directory of this archive | ||
8 | * for more details. | ||
9 | */ | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <linux/io.h> | ||
13 | #include <asm/mmu.h> | ||
14 | #include <asm/mmu_context.h> | ||
15 | |||
16 | static int __uses_jump_to_uncached fixed_pmb_init(void) | ||
17 | { | ||
18 | int i; | ||
19 | unsigned long addr, data; | ||
20 | |||
21 | jump_to_uncached(); | ||
22 | |||
23 | for (i = 0; i < PMB_ENTRY_MAX; i++) { | ||
24 | addr = PMB_DATA + (i << PMB_E_SHIFT); | ||
25 | data = ctrl_inl(addr); | ||
26 | if (!(data & PMB_V)) | ||
27 | continue; | ||
28 | |||
29 | if (data & PMB_C) { | ||
30 | #if defined(CONFIG_CACHE_WRITETHROUGH) | ||
31 | data |= PMB_WT; | ||
32 | #elif defined(CONFIG_CACHE_WRITEBACK) | ||
33 | data &= ~PMB_WT; | ||
34 | #else | ||
35 | data &= ~(PMB_C | PMB_WT); | ||
36 | #endif | ||
37 | } | ||
38 | ctrl_outl(data, addr); | ||
39 | } | ||
40 | |||
41 | back_to_cached(); | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | arch_initcall(fixed_pmb_init); | ||
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index aade31102112..280f6a166035 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c | |||
@@ -35,29 +35,9 @@ | |||
35 | 35 | ||
36 | static void __pmb_unmap(struct pmb_entry *); | 36 | static void __pmb_unmap(struct pmb_entry *); |
37 | 37 | ||
38 | static struct kmem_cache *pmb_cache; | 38 | static struct pmb_entry pmb_entry_list[NR_PMB_ENTRIES]; |
39 | static unsigned long pmb_map; | 39 | static unsigned long pmb_map; |
40 | 40 | ||
41 | static struct pmb_entry pmb_init_map[] = { | ||
42 | /* vpn ppn flags (ub/sz/c/wt) */ | ||
43 | |||
44 | /* P1 Section Mappings */ | ||
45 | { 0x80000000, 0x00000000, PMB_SZ_64M | PMB_C, }, | ||
46 | { 0x84000000, 0x04000000, PMB_SZ_64M | PMB_C, }, | ||
47 | { 0x88000000, 0x08000000, PMB_SZ_128M | PMB_C, }, | ||
48 | { 0x90000000, 0x10000000, PMB_SZ_64M | PMB_C, }, | ||
49 | { 0x94000000, 0x14000000, PMB_SZ_64M | PMB_C, }, | ||
50 | { 0x98000000, 0x18000000, PMB_SZ_64M | PMB_C, }, | ||
51 | |||
52 | /* P2 Section Mappings */ | ||
53 | { 0xa0000000, 0x00000000, PMB_UB | PMB_SZ_64M | PMB_WT, }, | ||
54 | { 0xa4000000, 0x04000000, PMB_UB | PMB_SZ_64M | PMB_WT, }, | ||
55 | { 0xa8000000, 0x08000000, PMB_UB | PMB_SZ_128M | PMB_WT, }, | ||
56 | { 0xb0000000, 0x10000000, PMB_UB | PMB_SZ_64M | PMB_WT, }, | ||
57 | { 0xb4000000, 0x14000000, PMB_UB | PMB_SZ_64M | PMB_WT, }, | ||
58 | { 0xb8000000, 0x18000000, PMB_UB | PMB_SZ_64M | PMB_WT, }, | ||
59 | }; | ||
60 | |||
61 | static inline unsigned long mk_pmb_entry(unsigned int entry) | 41 | static inline unsigned long mk_pmb_entry(unsigned int entry) |
62 | { | 42 | { |
63 | return (entry & PMB_E_MASK) << PMB_E_SHIFT; | 43 | return (entry & PMB_E_MASK) << PMB_E_SHIFT; |
@@ -73,81 +53,68 @@ static inline unsigned long mk_pmb_data(unsigned int entry) | |||
73 | return mk_pmb_entry(entry) | PMB_DATA; | 53 | return mk_pmb_entry(entry) | PMB_DATA; |
74 | } | 54 | } |
75 | 55 | ||
76 | static DEFINE_SPINLOCK(pmb_list_lock); | 56 | static int pmb_alloc_entry(void) |
77 | static struct pmb_entry *pmb_list; | ||
78 | |||
79 | static inline void pmb_list_add(struct pmb_entry *pmbe) | ||
80 | { | 57 | { |
81 | struct pmb_entry **p, *tmp; | 58 | unsigned int pos; |
82 | 59 | ||
83 | p = &pmb_list; | 60 | repeat: |
84 | while ((tmp = *p) != NULL) | 61 | pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES); |
85 | p = &tmp->next; | ||
86 | 62 | ||
87 | pmbe->next = tmp; | 63 | if (unlikely(pos > NR_PMB_ENTRIES)) |
88 | *p = pmbe; | 64 | return -ENOSPC; |
89 | } | ||
90 | 65 | ||
91 | static inline void pmb_list_del(struct pmb_entry *pmbe) | 66 | if (test_and_set_bit(pos, &pmb_map)) |
92 | { | 67 | goto repeat; |
93 | struct pmb_entry **p, *tmp; | ||
94 | 68 | ||
95 | for (p = &pmb_list; (tmp = *p); p = &tmp->next) | 69 | return pos; |
96 | if (tmp == pmbe) { | ||
97 | *p = tmp->next; | ||
98 | return; | ||
99 | } | ||
100 | } | 70 | } |
101 | 71 | ||
102 | struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn, | 72 | static struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn, |
103 | unsigned long flags) | 73 | unsigned long flags, int entry) |
104 | { | 74 | { |
105 | struct pmb_entry *pmbe; | 75 | struct pmb_entry *pmbe; |
76 | int pos; | ||
77 | |||
78 | if (entry == PMB_NO_ENTRY) { | ||
79 | pos = pmb_alloc_entry(); | ||
80 | if (pos < 0) | ||
81 | return ERR_PTR(pos); | ||
82 | } else { | ||
83 | if (test_bit(entry, &pmb_map)) | ||
84 | return ERR_PTR(-ENOSPC); | ||
85 | pos = entry; | ||
86 | } | ||
106 | 87 | ||
107 | pmbe = kmem_cache_alloc(pmb_cache, GFP_KERNEL); | 88 | pmbe = &pmb_entry_list[pos]; |
108 | if (!pmbe) | 89 | if (!pmbe) |
109 | return ERR_PTR(-ENOMEM); | 90 | return ERR_PTR(-ENOMEM); |
110 | 91 | ||
111 | pmbe->vpn = vpn; | 92 | pmbe->vpn = vpn; |
112 | pmbe->ppn = ppn; | 93 | pmbe->ppn = ppn; |
113 | pmbe->flags = flags; | 94 | pmbe->flags = flags; |
114 | 95 | pmbe->entry = pos; | |
115 | spin_lock_irq(&pmb_list_lock); | ||
116 | pmb_list_add(pmbe); | ||
117 | spin_unlock_irq(&pmb_list_lock); | ||
118 | 96 | ||
119 | return pmbe; | 97 | return pmbe; |
120 | } | 98 | } |
121 | 99 | ||
122 | void pmb_free(struct pmb_entry *pmbe) | 100 | static void pmb_free(struct pmb_entry *pmbe) |
123 | { | 101 | { |
124 | spin_lock_irq(&pmb_list_lock); | 102 | int pos = pmbe->entry; |
125 | pmb_list_del(pmbe); | ||
126 | spin_unlock_irq(&pmb_list_lock); | ||
127 | 103 | ||
128 | kmem_cache_free(pmb_cache, pmbe); | 104 | pmbe->vpn = 0; |
105 | pmbe->ppn = 0; | ||
106 | pmbe->flags = 0; | ||
107 | pmbe->entry = 0; | ||
108 | |||
109 | clear_bit(pos, &pmb_map); | ||
129 | } | 110 | } |
130 | 111 | ||
131 | /* | 112 | /* |
132 | * Must be in P2 for __set_pmb_entry() | 113 | * Must be in P2 for __set_pmb_entry() |
133 | */ | 114 | */ |
134 | int __set_pmb_entry(unsigned long vpn, unsigned long ppn, | 115 | static void __set_pmb_entry(unsigned long vpn, unsigned long ppn, |
135 | unsigned long flags, int *entry) | 116 | unsigned long flags, int pos) |
136 | { | 117 | { |
137 | unsigned int pos = *entry; | ||
138 | |||
139 | if (unlikely(pos == PMB_NO_ENTRY)) | ||
140 | pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES); | ||
141 | |||
142 | repeat: | ||
143 | if (unlikely(pos > NR_PMB_ENTRIES)) | ||
144 | return -ENOSPC; | ||
145 | |||
146 | if (test_and_set_bit(pos, &pmb_map)) { | ||
147 | pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES); | ||
148 | goto repeat; | ||
149 | } | ||
150 | |||
151 | ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos)); | 118 | ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos)); |
152 | 119 | ||
153 | #ifdef CONFIG_CACHE_WRITETHROUGH | 120 | #ifdef CONFIG_CACHE_WRITETHROUGH |
@@ -161,35 +128,21 @@ repeat: | |||
161 | #endif | 128 | #endif |
162 | 129 | ||
163 | ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos)); | 130 | ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos)); |
164 | |||
165 | *entry = pos; | ||
166 | |||
167 | return 0; | ||
168 | } | 131 | } |
169 | 132 | ||
170 | int __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe) | 133 | static void __uses_jump_to_uncached set_pmb_entry(struct pmb_entry *pmbe) |
171 | { | 134 | { |
172 | int ret; | ||
173 | |||
174 | jump_to_uncached(); | 135 | jump_to_uncached(); |
175 | ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry); | 136 | __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, pmbe->entry); |
176 | back_to_cached(); | 137 | back_to_cached(); |
177 | |||
178 | return ret; | ||
179 | } | 138 | } |
180 | 139 | ||
181 | void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe) | 140 | static void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe) |
182 | { | 141 | { |
183 | unsigned int entry = pmbe->entry; | 142 | unsigned int entry = pmbe->entry; |
184 | unsigned long addr; | 143 | unsigned long addr; |
185 | 144 | ||
186 | /* | 145 | if (unlikely(entry >= NR_PMB_ENTRIES)) |
187 | * Don't allow clearing of wired init entries, P1 or P2 access | ||
188 | * without a corresponding mapping in the PMB will lead to reset | ||
189 | * by the TLB. | ||
190 | */ | ||
191 | if (unlikely(entry < ARRAY_SIZE(pmb_init_map) || | ||
192 | entry >= NR_PMB_ENTRIES)) | ||
193 | return; | 146 | return; |
194 | 147 | ||
195 | jump_to_uncached(); | 148 | jump_to_uncached(); |
@@ -202,8 +155,6 @@ void __uses_jump_to_uncached clear_pmb_entry(struct pmb_entry *pmbe) | |||
202 | ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr); | 155 | ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr); |
203 | 156 | ||
204 | back_to_cached(); | 157 | back_to_cached(); |
205 | |||
206 | clear_bit(entry, &pmb_map); | ||
207 | } | 158 | } |
208 | 159 | ||
209 | 160 | ||
@@ -239,23 +190,17 @@ long pmb_remap(unsigned long vaddr, unsigned long phys, | |||
239 | 190 | ||
240 | again: | 191 | again: |
241 | for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) { | 192 | for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) { |
242 | int ret; | ||
243 | |||
244 | if (size < pmb_sizes[i].size) | 193 | if (size < pmb_sizes[i].size) |
245 | continue; | 194 | continue; |
246 | 195 | ||
247 | pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag); | 196 | pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag, |
197 | PMB_NO_ENTRY); | ||
248 | if (IS_ERR(pmbe)) { | 198 | if (IS_ERR(pmbe)) { |
249 | err = PTR_ERR(pmbe); | 199 | err = PTR_ERR(pmbe); |
250 | goto out; | 200 | goto out; |
251 | } | 201 | } |
252 | 202 | ||
253 | ret = set_pmb_entry(pmbe); | 203 | set_pmb_entry(pmbe); |
254 | if (ret != 0) { | ||
255 | pmb_free(pmbe); | ||
256 | err = -EBUSY; | ||
257 | goto out; | ||
258 | } | ||
259 | 204 | ||
260 | phys += pmb_sizes[i].size; | 205 | phys += pmb_sizes[i].size; |
261 | vaddr += pmb_sizes[i].size; | 206 | vaddr += pmb_sizes[i].size; |
@@ -292,11 +237,16 @@ out: | |||
292 | 237 | ||
293 | void pmb_unmap(unsigned long addr) | 238 | void pmb_unmap(unsigned long addr) |
294 | { | 239 | { |
295 | struct pmb_entry **p, *pmbe; | 240 | struct pmb_entry *pmbe = NULL; |
241 | int i; | ||
296 | 242 | ||
297 | for (p = &pmb_list; (pmbe = *p); p = &pmbe->next) | 243 | for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) { |
298 | if (pmbe->vpn == addr) | 244 | if (test_bit(i, &pmb_map)) { |
299 | break; | 245 | pmbe = &pmb_entry_list[i]; |
246 | if (pmbe->vpn == addr) | ||
247 | break; | ||
248 | } | ||
249 | } | ||
300 | 250 | ||
301 | if (unlikely(!pmbe)) | 251 | if (unlikely(!pmbe)) |
302 | return; | 252 | return; |
@@ -306,13 +256,22 @@ void pmb_unmap(unsigned long addr) | |||
306 | 256 | ||
307 | static void __pmb_unmap(struct pmb_entry *pmbe) | 257 | static void __pmb_unmap(struct pmb_entry *pmbe) |
308 | { | 258 | { |
309 | WARN_ON(!test_bit(pmbe->entry, &pmb_map)); | 259 | BUG_ON(!test_bit(pmbe->entry, &pmb_map)); |
310 | 260 | ||
311 | do { | 261 | do { |
312 | struct pmb_entry *pmblink = pmbe; | 262 | struct pmb_entry *pmblink = pmbe; |
313 | 263 | ||
314 | if (pmbe->entry != PMB_NO_ENTRY) | 264 | /* |
315 | clear_pmb_entry(pmbe); | 265 | * We may be called before this pmb_entry has been |
266 | * entered into the PMB table via set_pmb_entry(), but | ||
267 | * that's OK because we've allocated a unique slot for | ||
268 | * this entry in pmb_alloc() (even if we haven't filled | ||
269 | * it yet). | ||
270 | * | ||
271 | * Therefore, calling clear_pmb_entry() is safe as no | ||
272 | * other mapping can be using that slot. | ||
273 | */ | ||
274 | clear_pmb_entry(pmbe); | ||
316 | 275 | ||
317 | pmbe = pmblink->link; | 276 | pmbe = pmblink->link; |
318 | 277 | ||
@@ -320,42 +279,34 @@ static void __pmb_unmap(struct pmb_entry *pmbe) | |||
320 | } while (pmbe); | 279 | } while (pmbe); |
321 | } | 280 | } |
322 | 281 | ||
323 | static void pmb_cache_ctor(void *pmb) | 282 | #ifdef CONFIG_PMB |
283 | int __uses_jump_to_uncached pmb_init(void) | ||
324 | { | 284 | { |
325 | struct pmb_entry *pmbe = pmb; | 285 | unsigned int i; |
326 | 286 | long size, ret; | |
327 | memset(pmb, 0, sizeof(struct pmb_entry)); | ||
328 | |||
329 | pmbe->entry = PMB_NO_ENTRY; | ||
330 | } | ||
331 | |||
332 | static int __uses_jump_to_uncached pmb_init(void) | ||
333 | { | ||
334 | unsigned int nr_entries = ARRAY_SIZE(pmb_init_map); | ||
335 | unsigned int entry, i; | ||
336 | |||
337 | BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES)); | ||
338 | |||
339 | pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry), 0, | ||
340 | SLAB_PANIC, pmb_cache_ctor); | ||
341 | 287 | ||
342 | jump_to_uncached(); | 288 | jump_to_uncached(); |
343 | 289 | ||
344 | /* | 290 | /* |
345 | * Ordering is important, P2 must be mapped in the PMB before we | 291 | * Insert PMB entries for the P1 and P2 areas so that, after |
346 | * can set PMB.SE, and P1 must be mapped before we jump back to | 292 | * we've switched the MMU to 32-bit mode, the semantics of P1 |
347 | * P1 space. | 293 | * and P2 are the same as in 29-bit mode, e.g. |
294 | * | ||
295 | * P1 - provides a cached window onto physical memory | ||
296 | * P2 - provides an uncached window onto physical memory | ||
348 | */ | 297 | */ |
349 | for (entry = 0; entry < nr_entries; entry++) { | 298 | size = __MEMORY_START + __MEMORY_SIZE; |
350 | struct pmb_entry *pmbe = pmb_init_map + entry; | ||
351 | 299 | ||
352 | __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &entry); | 300 | ret = pmb_remap(P1SEG, 0x00000000, size, PMB_C); |
353 | } | 301 | BUG_ON(ret != size); |
302 | |||
303 | ret = pmb_remap(P2SEG, 0x00000000, size, PMB_WT | PMB_UB); | ||
304 | BUG_ON(ret != size); | ||
354 | 305 | ||
355 | ctrl_outl(0, PMB_IRMCR); | 306 | ctrl_outl(0, PMB_IRMCR); |
356 | 307 | ||
357 | /* PMB.SE and UB[7] */ | 308 | /* PMB.SE and UB[7] */ |
358 | ctrl_outl((1 << 31) | (1 << 7), PMB_PASCR); | 309 | ctrl_outl(PASCR_SE | (1 << 7), PMB_PASCR); |
359 | 310 | ||
360 | /* Flush out the TLB */ | 311 | /* Flush out the TLB */ |
361 | i = ctrl_inl(MMUCR); | 312 | i = ctrl_inl(MMUCR); |
@@ -366,7 +317,53 @@ static int __uses_jump_to_uncached pmb_init(void) | |||
366 | 317 | ||
367 | return 0; | 318 | return 0; |
368 | } | 319 | } |
369 | arch_initcall(pmb_init); | 320 | #else |
321 | int __uses_jump_to_uncached pmb_init(void) | ||
322 | { | ||
323 | int i; | ||
324 | unsigned long addr, data; | ||
325 | |||
326 | jump_to_uncached(); | ||
327 | |||
328 | for (i = 0; i < PMB_ENTRY_MAX; i++) { | ||
329 | struct pmb_entry *pmbe; | ||
330 | unsigned long vpn, ppn, flags; | ||
331 | |||
332 | addr = PMB_DATA + (i << PMB_E_SHIFT); | ||
333 | data = ctrl_inl(addr); | ||
334 | if (!(data & PMB_V)) | ||
335 | continue; | ||
336 | |||
337 | if (data & PMB_C) { | ||
338 | #if defined(CONFIG_CACHE_WRITETHROUGH) | ||
339 | data |= PMB_WT; | ||
340 | #elif defined(CONFIG_CACHE_WRITEBACK) | ||
341 | data &= ~PMB_WT; | ||
342 | #else | ||
343 | data &= ~(PMB_C | PMB_WT); | ||
344 | #endif | ||
345 | } | ||
346 | ctrl_outl(data, addr); | ||
347 | |||
348 | ppn = data & PMB_PFN_MASK; | ||
349 | |||
350 | flags = data & (PMB_C | PMB_WT | PMB_UB); | ||
351 | flags |= data & PMB_SZ_MASK; | ||
352 | |||
353 | addr = PMB_ADDR + (i << PMB_E_SHIFT); | ||
354 | data = ctrl_inl(addr); | ||
355 | |||
356 | vpn = data & PMB_PFN_MASK; | ||
357 | |||
358 | pmbe = pmb_alloc(vpn, ppn, flags, i); | ||
359 | WARN_ON(IS_ERR(pmbe)); | ||
360 | } | ||
361 | |||
362 | back_to_cached(); | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | #endif /* CONFIG_PMB */ | ||
370 | 367 | ||
371 | static int pmb_seq_show(struct seq_file *file, void *iter) | 368 | static int pmb_seq_show(struct seq_file *file, void *iter) |
372 | { | 369 | { |
@@ -434,15 +431,18 @@ postcore_initcall(pmb_debugfs_init); | |||
434 | static int pmb_sysdev_suspend(struct sys_device *dev, pm_message_t state) | 431 | static int pmb_sysdev_suspend(struct sys_device *dev, pm_message_t state) |
435 | { | 432 | { |
436 | static pm_message_t prev_state; | 433 | static pm_message_t prev_state; |
434 | int i; | ||
437 | 435 | ||
438 | /* Restore the PMB after a resume from hibernation */ | 436 | /* Restore the PMB after a resume from hibernation */ |
439 | if (state.event == PM_EVENT_ON && | 437 | if (state.event == PM_EVENT_ON && |
440 | prev_state.event == PM_EVENT_FREEZE) { | 438 | prev_state.event == PM_EVENT_FREEZE) { |
441 | struct pmb_entry *pmbe; | 439 | struct pmb_entry *pmbe; |
442 | spin_lock_irq(&pmb_list_lock); | 440 | for (i = 0; i < ARRAY_SIZE(pmb_entry_list); i++) { |
443 | for (pmbe = pmb_list; pmbe; pmbe = pmbe->next) | 441 | if (test_bit(i, &pmb_map)) { |
444 | set_pmb_entry(pmbe); | 442 | pmbe = &pmb_entry_list[i]; |
445 | spin_unlock_irq(&pmb_list_lock); | 443 | set_pmb_entry(pmbe); |
444 | } | ||
445 | } | ||
446 | } | 446 | } |
447 | prev_state = state; | 447 | prev_state = state; |
448 | return 0; | 448 | return 0; |
diff --git a/arch/sh/oprofile/Makefile b/arch/sh/oprofile/Makefile index 8e6eec91c14c..4886c5c1786c 100644 --- a/arch/sh/oprofile/Makefile +++ b/arch/sh/oprofile/Makefile | |||
@@ -7,7 +7,3 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \ | |||
7 | timer_int.o ) | 7 | timer_int.o ) |
8 | 8 | ||
9 | oprofile-y := $(DRIVER_OBJS) common.o backtrace.o | 9 | oprofile-y := $(DRIVER_OBJS) common.o backtrace.o |
10 | |||
11 | oprofile-$(CONFIG_CPU_SUBTYPE_SH7750S) += op_model_sh7750.o | ||
12 | oprofile-$(CONFIG_CPU_SUBTYPE_SH7750) += op_model_sh7750.o | ||
13 | oprofile-$(CONFIG_CPU_SUBTYPE_SH7091) += op_model_sh7750.o | ||
diff --git a/arch/sh/oprofile/common.c b/arch/sh/oprofile/common.c index 44f4e31c6d63..ac604937f3ee 100644 --- a/arch/sh/oprofile/common.c +++ b/arch/sh/oprofile/common.c | |||
@@ -20,9 +20,6 @@ | |||
20 | #include <asm/processor.h> | 20 | #include <asm/processor.h> |
21 | #include "op_impl.h" | 21 | #include "op_impl.h" |
22 | 22 | ||
23 | extern struct op_sh_model op_model_sh7750_ops __weak; | ||
24 | extern struct op_sh_model op_model_sh4a_ops __weak; | ||
25 | |||
26 | static struct op_sh_model *model; | 23 | static struct op_sh_model *model; |
27 | 24 | ||
28 | static struct op_counter_config ctr[20]; | 25 | static struct op_counter_config ctr[20]; |
@@ -94,33 +91,14 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) | |||
94 | */ | 91 | */ |
95 | ops->backtrace = sh_backtrace; | 92 | ops->backtrace = sh_backtrace; |
96 | 93 | ||
97 | switch (current_cpu_data.type) { | 94 | /* |
98 | /* SH-4 types */ | 95 | * XXX |
99 | case CPU_SH7750: | 96 | * |
100 | case CPU_SH7750S: | 97 | * All of the SH7750/SH-4A counters have been converted to perf, |
101 | lmodel = &op_model_sh7750_ops; | 98 | * this infrastructure hook is left for other users until they've |
102 | break; | 99 | * had a chance to convert over, at which point all of this |
103 | 100 | * will be deleted. | |
104 | /* SH-4A types */ | 101 | */ |
105 | case CPU_SH7763: | ||
106 | case CPU_SH7770: | ||
107 | case CPU_SH7780: | ||
108 | case CPU_SH7781: | ||
109 | case CPU_SH7785: | ||
110 | case CPU_SH7786: | ||
111 | case CPU_SH7723: | ||
112 | case CPU_SH7724: | ||
113 | case CPU_SHX3: | ||
114 | lmodel = &op_model_sh4a_ops; | ||
115 | break; | ||
116 | |||
117 | /* SH4AL-DSP types */ | ||
118 | case CPU_SH7343: | ||
119 | case CPU_SH7722: | ||
120 | case CPU_SH7366: | ||
121 | lmodel = &op_model_sh4a_ops; | ||
122 | break; | ||
123 | } | ||
124 | 102 | ||
125 | if (!lmodel) | 103 | if (!lmodel) |
126 | return -ENODEV; | 104 | return -ENODEV; |
diff --git a/arch/sh/oprofile/op_impl.h b/arch/sh/oprofile/op_impl.h index 4d509975eba6..1244479ceb29 100644 --- a/arch/sh/oprofile/op_impl.h +++ b/arch/sh/oprofile/op_impl.h | |||
@@ -6,7 +6,7 @@ struct op_counter_config { | |||
6 | unsigned long enabled; | 6 | unsigned long enabled; |
7 | unsigned long event; | 7 | unsigned long event; |
8 | 8 | ||
9 | unsigned long long count; | 9 | unsigned long count; |
10 | 10 | ||
11 | /* Dummy values for userspace tool compliance */ | 11 | /* Dummy values for userspace tool compliance */ |
12 | unsigned long kernel; | 12 | unsigned long kernel; |
diff --git a/arch/sh/oprofile/op_model_sh7750.c b/arch/sh/oprofile/op_model_sh7750.c deleted file mode 100644 index c892c7c30c2f..000000000000 --- a/arch/sh/oprofile/op_model_sh7750.c +++ /dev/null | |||
@@ -1,255 +0,0 @@ | |||
1 | /* | ||
2 | * arch/sh/oprofile/op_model_sh7750.c | ||
3 | * | ||
4 | * OProfile support for SH7750/SH7750S Performance Counters | ||
5 | * | ||
6 | * Copyright (C) 2003 - 2008 Paul Mundt | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file "COPYING" in the main directory of this archive | ||
10 | * for more details. | ||
11 | */ | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/oprofile.h> | ||
14 | #include <linux/profile.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/io.h> | ||
19 | #include <linux/fs.h> | ||
20 | #include "op_impl.h" | ||
21 | |||
22 | #define PM_CR_BASE 0xff000084 /* 16-bit */ | ||
23 | #define PM_CTR_BASE 0xff100004 /* 32-bit */ | ||
24 | |||
25 | #define PMCR(n) (PM_CR_BASE + ((n) * 0x04)) | ||
26 | #define PMCTRH(n) (PM_CTR_BASE + 0x00 + ((n) * 0x08)) | ||
27 | #define PMCTRL(n) (PM_CTR_BASE + 0x04 + ((n) * 0x08)) | ||
28 | |||
29 | #define PMCR_PMM_MASK 0x0000003f | ||
30 | |||
31 | #define PMCR_CLKF 0x00000100 | ||
32 | #define PMCR_PMCLR 0x00002000 | ||
33 | #define PMCR_PMST 0x00004000 | ||
34 | #define PMCR_PMEN 0x00008000 | ||
35 | |||
36 | struct op_sh_model op_model_sh7750_ops; | ||
37 | |||
38 | #define NR_CNTRS 2 | ||
39 | |||
40 | static struct sh7750_ppc_register_config { | ||
41 | unsigned int ctrl; | ||
42 | unsigned long cnt_hi; | ||
43 | unsigned long cnt_lo; | ||
44 | } regcache[NR_CNTRS]; | ||
45 | |||
46 | /* | ||
47 | * There are a number of events supported by each counter (33 in total). | ||
48 | * Since we have 2 counters, each counter will take the event code as it | ||
49 | * corresponds to the PMCR PMM setting. Each counter can be configured | ||
50 | * independently. | ||
51 | * | ||
52 | * Event Code Description | ||
53 | * ---------- ----------- | ||
54 | * | ||
55 | * 0x01 Operand read access | ||
56 | * 0x02 Operand write access | ||
57 | * 0x03 UTLB miss | ||
58 | * 0x04 Operand cache read miss | ||
59 | * 0x05 Operand cache write miss | ||
60 | * 0x06 Instruction fetch (w/ cache) | ||
61 | * 0x07 Instruction TLB miss | ||
62 | * 0x08 Instruction cache miss | ||
63 | * 0x09 All operand accesses | ||
64 | * 0x0a All instruction accesses | ||
65 | * 0x0b OC RAM operand access | ||
66 | * 0x0d On-chip I/O space access | ||
67 | * 0x0e Operand access (r/w) | ||
68 | * 0x0f Operand cache miss (r/w) | ||
69 | * 0x10 Branch instruction | ||
70 | * 0x11 Branch taken | ||
71 | * 0x12 BSR/BSRF/JSR | ||
72 | * 0x13 Instruction execution | ||
73 | * 0x14 Instruction execution in parallel | ||
74 | * 0x15 FPU Instruction execution | ||
75 | * 0x16 Interrupt | ||
76 | * 0x17 NMI | ||
77 | * 0x18 trapa instruction execution | ||
78 | * 0x19 UBCA match | ||
79 | * 0x1a UBCB match | ||
80 | * 0x21 Instruction cache fill | ||
81 | * 0x22 Operand cache fill | ||
82 | * 0x23 Elapsed time | ||
83 | * 0x24 Pipeline freeze by I-cache miss | ||
84 | * 0x25 Pipeline freeze by D-cache miss | ||
85 | * 0x27 Pipeline freeze by branch instruction | ||
86 | * 0x28 Pipeline freeze by CPU register | ||
87 | * 0x29 Pipeline freeze by FPU | ||
88 | * | ||
89 | * Unfortunately we don't have a native exception or interrupt for counter | ||
90 | * overflow (although since these counters can run for 16.3 days without | ||
91 | * overflowing, it's not really necessary). | ||
92 | * | ||
93 | * OProfile on the other hand likes to have samples taken periodically, so | ||
94 | * for now we just piggyback the timer interrupt to get the expected | ||
95 | * behavior. | ||
96 | */ | ||
97 | |||
98 | static int sh7750_timer_notify(struct pt_regs *regs) | ||
99 | { | ||
100 | oprofile_add_sample(regs, 0); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static u64 sh7750_read_counter(int counter) | ||
105 | { | ||
106 | return (u64)((u64)(__raw_readl(PMCTRH(counter)) & 0xffff) << 32) | | ||
107 | __raw_readl(PMCTRL(counter)); | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * Files will be in a path like: | ||
112 | * | ||
113 | * /<oprofilefs mount point>/<counter number>/<file> | ||
114 | * | ||
115 | * So when dealing with <file>, we look to the parent dentry for the counter | ||
116 | * number. | ||
117 | */ | ||
118 | static inline int to_counter(struct file *file) | ||
119 | { | ||
120 | const unsigned char *name = file->f_path.dentry->d_parent->d_name.name; | ||
121 | |||
122 | return (int)simple_strtol(name, NULL, 10); | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * XXX: We have 48-bit counters, so we're probably going to want something | ||
127 | * more along the lines of oprofilefs_ullong_to_user().. Truncating to | ||
128 | * unsigned long works fine for now though, as long as we don't attempt to | ||
129 | * profile for too horribly long. | ||
130 | */ | ||
131 | static ssize_t sh7750_read_count(struct file *file, char __user *buf, | ||
132 | size_t count, loff_t *ppos) | ||
133 | { | ||
134 | int counter = to_counter(file); | ||
135 | u64 val = sh7750_read_counter(counter); | ||
136 | |||
137 | return oprofilefs_ulong_to_user((unsigned long)val, buf, count, ppos); | ||
138 | } | ||
139 | |||
140 | static ssize_t sh7750_write_count(struct file *file, const char __user *buf, | ||
141 | size_t count, loff_t *ppos) | ||
142 | { | ||
143 | int counter = to_counter(file); | ||
144 | unsigned long val; | ||
145 | |||
146 | if (oprofilefs_ulong_from_user(&val, buf, count)) | ||
147 | return -EFAULT; | ||
148 | |||
149 | /* | ||
150 | * Any write will clear the counter, although only 0 should be | ||
151 | * written for this purpose, as we do not support setting the | ||
152 | * counter to an arbitrary value. | ||
153 | */ | ||
154 | WARN_ON(val != 0); | ||
155 | |||
156 | __raw_writew(__raw_readw(PMCR(counter)) | PMCR_PMCLR, PMCR(counter)); | ||
157 | |||
158 | return count; | ||
159 | } | ||
160 | |||
161 | static const struct file_operations count_fops = { | ||
162 | .read = sh7750_read_count, | ||
163 | .write = sh7750_write_count, | ||
164 | }; | ||
165 | |||
166 | static int sh7750_ppc_create_files(struct super_block *sb, struct dentry *dir) | ||
167 | { | ||
168 | return oprofilefs_create_file(sb, dir, "count", &count_fops); | ||
169 | } | ||
170 | |||
171 | static void sh7750_ppc_reg_setup(struct op_counter_config *ctr) | ||
172 | { | ||
173 | unsigned int counters = op_model_sh7750_ops.num_counters; | ||
174 | int i; | ||
175 | |||
176 | for (i = 0; i < counters; i++) { | ||
177 | regcache[i].ctrl = 0; | ||
178 | regcache[i].cnt_hi = 0; | ||
179 | regcache[i].cnt_lo = 0; | ||
180 | |||
181 | if (!ctr[i].enabled) | ||
182 | continue; | ||
183 | |||
184 | regcache[i].ctrl |= ctr[i].event | PMCR_PMEN | PMCR_PMST; | ||
185 | regcache[i].cnt_hi = (unsigned long)((ctr->count >> 32) & 0xffff); | ||
186 | regcache[i].cnt_lo = (unsigned long)(ctr->count & 0xffffffff); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | static void sh7750_ppc_cpu_setup(void *args) | ||
191 | { | ||
192 | unsigned int counters = op_model_sh7750_ops.num_counters; | ||
193 | int i; | ||
194 | |||
195 | for (i = 0; i < counters; i++) { | ||
196 | __raw_writew(0, PMCR(i)); | ||
197 | __raw_writel(regcache[i].cnt_hi, PMCTRH(i)); | ||
198 | __raw_writel(regcache[i].cnt_lo, PMCTRL(i)); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | static void sh7750_ppc_cpu_start(void *args) | ||
203 | { | ||
204 | unsigned int counters = op_model_sh7750_ops.num_counters; | ||
205 | int i; | ||
206 | |||
207 | for (i = 0; i < counters; i++) | ||
208 | __raw_writew(regcache[i].ctrl, PMCR(i)); | ||
209 | } | ||
210 | |||
211 | static void sh7750_ppc_cpu_stop(void *args) | ||
212 | { | ||
213 | unsigned int counters = op_model_sh7750_ops.num_counters; | ||
214 | int i; | ||
215 | |||
216 | /* Disable the counters */ | ||
217 | for (i = 0; i < counters; i++) | ||
218 | __raw_writew(__raw_readw(PMCR(i)) & ~PMCR_PMEN, PMCR(i)); | ||
219 | } | ||
220 | |||
221 | static inline void sh7750_ppc_reset(void) | ||
222 | { | ||
223 | unsigned int counters = op_model_sh7750_ops.num_counters; | ||
224 | int i; | ||
225 | |||
226 | /* Clear the counters */ | ||
227 | for (i = 0; i < counters; i++) | ||
228 | __raw_writew(__raw_readw(PMCR(i)) | PMCR_PMCLR, PMCR(i)); | ||
229 | } | ||
230 | |||
231 | static int sh7750_ppc_init(void) | ||
232 | { | ||
233 | sh7750_ppc_reset(); | ||
234 | |||
235 | return register_timer_hook(sh7750_timer_notify); | ||
236 | } | ||
237 | |||
238 | static void sh7750_ppc_exit(void) | ||
239 | { | ||
240 | unregister_timer_hook(sh7750_timer_notify); | ||
241 | |||
242 | sh7750_ppc_reset(); | ||
243 | } | ||
244 | |||
245 | struct op_sh_model op_model_sh7750_ops = { | ||
246 | .cpu_type = "sh/sh7750", | ||
247 | .num_counters = NR_CNTRS, | ||
248 | .reg_setup = sh7750_ppc_reg_setup, | ||
249 | .cpu_setup = sh7750_ppc_cpu_setup, | ||
250 | .cpu_start = sh7750_ppc_cpu_start, | ||
251 | .cpu_stop = sh7750_ppc_cpu_stop, | ||
252 | .init = sh7750_ppc_init, | ||
253 | .exit = sh7750_ppc_exit, | ||
254 | .create_files = sh7750_ppc_create_files, | ||
255 | }; | ||