diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-08-06 09:00:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-08-06 09:00:05 -0400 |
commit | 1630e843e104528ddf0208dfc692c70c9bd05a89 (patch) | |
tree | b75d583b719a0b1398162aceccf2f443e7d36858 | |
parent | 194d6ad32e1eef433c61040385dcfd98e6fe2ef9 (diff) | |
parent | e61c10e468a42512f5fad74c00b62af5cc19f65f (diff) |
Merge tag 'sh-for-4.8' of git://git.libc.org/linux-sh
Pull arch/sh updates from Rich Felker:
"These changes improve device tree support (including builtin DTB), add
support for the J-Core J2 processor, an open source synthesizable
reimplementation of the SH-2 ISA, resolve a longstanding sigcontext
ABI mismatch issue, and fix various bugs including nommu-specific
issues and minor regressions introduced in 4.6.
The J-Core arch support is included here but to be usable it needs
drivers that are waiting on approval/inclusion from their subsystem
maintainers"
* tag 'sh-for-4.8' of git://git.libc.org/linux-sh: (23 commits)
sh: add device tree source for J2 FPGA on Mimas v2 board
sh: add defconfig for J-Core J2
sh: use common clock framework with device tree boards
sh: system call wire up
sh: Delete unnecessary checks before the function call "mempool_destroy"
sh: do not perform IPI-based cache flush except on boards that need it
sh: add SMP support for J2
sh: SMP support for SH2 entry.S
sh: add working futex atomic ops on userspace addresses for smp
sh: add J2 atomics using the cas.l instruction
sh: add AT_HWCAP flag for J-Core cas.l instruction
sh: add support for J-Core J2 processor
sh: fix build regression with CONFIG_OF && !CONFIG_OF_FLATTREE
sh: allow clocksource drivers to register sched_clock backends
sh: make heartbeat driver explicitly non-modular
sh: make board-secureedge5410 explicitly non-modular
sh: make mm/asids-debugfs explicitly non-modular
sh: make time.c explicitly non-modular
sh: fix futex/robust_list on nommu models
sh: disable aliased page logic on NOMMU models
...
45 files changed, 1206 insertions, 399 deletions
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 0d5f3a9bb315..ee086958b2b2 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig | |||
@@ -38,6 +38,7 @@ config SUPERH | |||
38 | select GENERIC_IDLE_POLL_SETUP | 38 | select GENERIC_IDLE_POLL_SETUP |
39 | select GENERIC_CLOCKEVENTS | 39 | select GENERIC_CLOCKEVENTS |
40 | select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST | 40 | select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST |
41 | select GENERIC_SCHED_CLOCK | ||
41 | select GENERIC_STRNCPY_FROM_USER | 42 | select GENERIC_STRNCPY_FROM_USER |
42 | select GENERIC_STRNLEN_USER | 43 | select GENERIC_STRNLEN_USER |
43 | select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER | 44 | select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER |
@@ -45,6 +46,7 @@ config SUPERH | |||
45 | select OLD_SIGSUSPEND | 46 | select OLD_SIGSUSPEND |
46 | select OLD_SIGACTION | 47 | select OLD_SIGACTION |
47 | select HAVE_ARCH_AUDITSYSCALL | 48 | select HAVE_ARCH_AUDITSYSCALL |
49 | select HAVE_FUTEX_CMPXCHG if FUTEX | ||
48 | select HAVE_NMI | 50 | select HAVE_NMI |
49 | help | 51 | help |
50 | The SuperH is a RISC processor targeted for use in embedded systems | 52 | The SuperH is a RISC processor targeted for use in embedded systems |
@@ -184,6 +186,12 @@ config CPU_SH2A | |||
184 | select CPU_SH2 | 186 | select CPU_SH2 |
185 | select UNCACHED_MAPPING | 187 | select UNCACHED_MAPPING |
186 | 188 | ||
189 | config CPU_J2 | ||
190 | bool | ||
191 | select CPU_SH2 | ||
192 | select OF | ||
193 | select OF_EARLY_FLATTREE | ||
194 | |||
187 | config CPU_SH3 | 195 | config CPU_SH3 |
188 | bool | 196 | bool |
189 | select CPU_HAS_INTEVT | 197 | select CPU_HAS_INTEVT |
@@ -250,6 +258,12 @@ config CPU_SUBTYPE_SH7619 | |||
250 | select CPU_SH2 | 258 | select CPU_SH2 |
251 | select SYS_SUPPORTS_SH_CMT | 259 | select SYS_SUPPORTS_SH_CMT |
252 | 260 | ||
261 | config CPU_SUBTYPE_J2 | ||
262 | bool "Support J2 processor" | ||
263 | select CPU_J2 | ||
264 | select SYS_SUPPORTS_SMP | ||
265 | select GENERIC_CLOCKEVENTS_BROADCAST if SMP | ||
266 | |||
253 | # SH-2A Processor Support | 267 | # SH-2A Processor Support |
254 | 268 | ||
255 | config CPU_SUBTYPE_SH7201 | 269 | config CPU_SUBTYPE_SH7201 |
@@ -739,6 +753,26 @@ endmenu | |||
739 | 753 | ||
740 | menu "Boot options" | 754 | menu "Boot options" |
741 | 755 | ||
756 | config USE_BUILTIN_DTB | ||
757 | bool "Use builtin DTB" | ||
758 | default n | ||
759 | depends on SH_DEVICE_TREE | ||
760 | help | ||
761 | Link a device tree blob for particular hardware into the kernel, | ||
762 | suppressing use of the DTB pointer provided by the bootloader. | ||
763 | This option should only be used with legacy bootloaders that are | ||
764 | not capable of providing a DTB to the kernel, or for experimental | ||
765 | hardware without stable device tree bindings. | ||
766 | |||
767 | config BUILTIN_DTB_SOURCE | ||
768 | string "Source file for builtin DTB" | ||
769 | default "" | ||
770 | depends on USE_BUILTIN_DTB | ||
771 | help | ||
772 | Base name (without suffix, relative to arch/sh/boot/dts) for the | ||
773 | a DTS file that will be used to produce the DTB linked into the | ||
774 | kernel. | ||
775 | |||
742 | config ZERO_PAGE_OFFSET | 776 | config ZERO_PAGE_OFFSET |
743 | hex | 777 | hex |
744 | default "0x00010000" if PAGE_SIZE_64KB || SH_RTS7751R2D || \ | 778 | default "0x00010000" if PAGE_SIZE_64KB || SH_RTS7751R2D || \ |
diff --git a/arch/sh/Makefile b/arch/sh/Makefile index bf5b3f5f4962..00476662ac2c 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile | |||
@@ -31,6 +31,7 @@ isa-y := $(isa-y)-up | |||
31 | endif | 31 | endif |
32 | 32 | ||
33 | cflags-$(CONFIG_CPU_SH2) := $(call cc-option,-m2,) | 33 | cflags-$(CONFIG_CPU_SH2) := $(call cc-option,-m2,) |
34 | cflags-$(CONFIG_CPU_J2) := $(call cc-option,-mj2,) | ||
34 | cflags-$(CONFIG_CPU_SH2A) += $(call cc-option,-m2a,) \ | 35 | cflags-$(CONFIG_CPU_SH2A) += $(call cc-option,-m2a,) \ |
35 | $(call cc-option,-m2a-nofpu,) \ | 36 | $(call cc-option,-m2a-nofpu,) \ |
36 | $(call cc-option,-m4-nofpu,) | 37 | $(call cc-option,-m4-nofpu,) |
@@ -130,6 +131,8 @@ head-y := arch/sh/kernel/head_$(BITS).o | |||
130 | core-y += arch/sh/kernel/ arch/sh/mm/ arch/sh/boards/ | 131 | core-y += arch/sh/kernel/ arch/sh/mm/ arch/sh/boards/ |
131 | core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/ | 132 | core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/ |
132 | 133 | ||
134 | core-$(CONFIG_USE_BUILTIN_DTB) += arch/sh/boot/dts/ | ||
135 | |||
133 | # Mach groups | 136 | # Mach groups |
134 | machdir-$(CONFIG_SOLUTION_ENGINE) += mach-se | 137 | machdir-$(CONFIG_SOLUTION_ENGINE) += mach-se |
135 | machdir-$(CONFIG_SH_HP6XX) += mach-hp6xx | 138 | machdir-$(CONFIG_SH_HP6XX) += mach-hp6xx |
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig index e0db04664e2e..e9c2c42031fe 100644 --- a/arch/sh/boards/Kconfig +++ b/arch/sh/boards/Kconfig | |||
@@ -11,6 +11,7 @@ config SH_DEVICE_TREE | |||
11 | select OF | 11 | select OF |
12 | select OF_EARLY_FLATTREE | 12 | select OF_EARLY_FLATTREE |
13 | select CLKSRC_OF | 13 | select CLKSRC_OF |
14 | select COMMON_CLK | ||
14 | select GENERIC_CALIBRATE_DELAY | 15 | select GENERIC_CALIBRATE_DELAY |
15 | help | 16 | help |
16 | Select Board Described by Device Tree to build a kernel that | 17 | Select Board Described by Device Tree to build a kernel that |
diff --git a/arch/sh/boards/board-secureedge5410.c b/arch/sh/boards/board-secureedge5410.c index 98b36205aa7b..97ec67ffec2b 100644 --- a/arch/sh/boards/board-secureedge5410.c +++ b/arch/sh/boards/board-secureedge5410.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/timer.h> | 15 | #include <linux/timer.h> |
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/module.h> | ||
18 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
19 | #include <asm/machvec.h> | 18 | #include <asm/machvec.h> |
20 | #include <mach/secureedge5410.h> | 19 | #include <mach/secureedge5410.h> |
@@ -49,7 +48,7 @@ static int __init eraseconfig_init(void) | |||
49 | irq); | 48 | irq); |
50 | return 0; | 49 | return 0; |
51 | } | 50 | } |
52 | module_init(eraseconfig_init); | 51 | device_initcall(eraseconfig_init); |
53 | 52 | ||
54 | /* | 53 | /* |
55 | * Initialize IRQ setting | 54 | * Initialize IRQ setting |
diff --git a/arch/sh/boards/of-generic.c b/arch/sh/boards/of-generic.c index 911ffb9f115b..1fb6d5714bae 100644 --- a/arch/sh/boards/of-generic.c +++ b/arch/sh/boards/of-generic.c | |||
@@ -124,13 +124,22 @@ static void __init sh_of_time_init(void) | |||
124 | 124 | ||
125 | static void __init sh_of_setup(char **cmdline_p) | 125 | static void __init sh_of_setup(char **cmdline_p) |
126 | { | 126 | { |
127 | struct device_node *root; | ||
128 | |||
129 | #ifdef CONFIG_USE_BUILTIN_DTB | ||
130 | unflatten_and_copy_device_tree(); | ||
131 | #else | ||
127 | unflatten_device_tree(); | 132 | unflatten_device_tree(); |
133 | #endif | ||
128 | 134 | ||
129 | board_time_init = sh_of_time_init; | 135 | board_time_init = sh_of_time_init; |
130 | 136 | ||
131 | sh_mv.mv_name = of_flat_dt_get_machine_name(); | 137 | sh_mv.mv_name = "Unknown SH model"; |
132 | if (!sh_mv.mv_name) | 138 | root = of_find_node_by_path("/"); |
133 | sh_mv.mv_name = "Unknown SH model"; | 139 | if (root) { |
140 | of_property_read_string(root, "model", &sh_mv.mv_name); | ||
141 | of_node_put(root); | ||
142 | } | ||
134 | 143 | ||
135 | sh_of_smp_probe(); | 144 | sh_of_smp_probe(); |
136 | } | 145 | } |
diff --git a/arch/sh/boot/dts/Makefile b/arch/sh/boot/dts/Makefile new file mode 100644 index 000000000000..e5ce3a0de7f4 --- /dev/null +++ b/arch/sh/boot/dts/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o | ||
2 | |||
3 | clean-files := *.dtb.S | ||
diff --git a/arch/sh/boot/dts/j2_mimas_v2.dts b/arch/sh/boot/dts/j2_mimas_v2.dts new file mode 100755 index 000000000000..880de75360b3 --- /dev/null +++ b/arch/sh/boot/dts/j2_mimas_v2.dts | |||
@@ -0,0 +1,96 @@ | |||
1 | /dts-v1/; | ||
2 | |||
3 | / { | ||
4 | compatible = "jcore,j2-soc"; | ||
5 | model = "J2 FPGA SoC on Mimas v2 board"; | ||
6 | |||
7 | #address-cells = <1>; | ||
8 | #size-cells = <1>; | ||
9 | |||
10 | interrupt-parent = <&aic>; | ||
11 | |||
12 | cpus { | ||
13 | #address-cells = <1>; | ||
14 | #size-cells = <0>; | ||
15 | |||
16 | cpu@0 { | ||
17 | device_type = "cpu"; | ||
18 | compatible = "jcore,j2"; | ||
19 | reg = <0>; | ||
20 | clock-frequency = <50000000>; | ||
21 | d-cache-size = <8192>; | ||
22 | i-cache-size = <8192>; | ||
23 | d-cache-block-size = <16>; | ||
24 | i-cache-block-size = <16>; | ||
25 | }; | ||
26 | }; | ||
27 | |||
28 | memory@10000000 { | ||
29 | device_type = "memory"; | ||
30 | reg = <0x10000000 0x4000000>; | ||
31 | }; | ||
32 | |||
33 | aliases { | ||
34 | serial0 = &uart0; | ||
35 | spi0 = &spi0; | ||
36 | }; | ||
37 | |||
38 | chosen { | ||
39 | stdout-path = "serial0"; | ||
40 | }; | ||
41 | |||
42 | soc@abcd0000 { | ||
43 | compatible = "simple-bus"; | ||
44 | ranges = <0 0xabcd0000 0x100000>; | ||
45 | |||
46 | #address-cells = <1>; | ||
47 | #size-cells = <1>; | ||
48 | |||
49 | aic: interrupt-controller@200 { | ||
50 | compatible = "jcore,aic1"; | ||
51 | reg = <0x200 0x10>; | ||
52 | interrupt-controller; | ||
53 | #interrupt-cells = <1>; | ||
54 | }; | ||
55 | |||
56 | cache-controller@c0 { | ||
57 | compatible = "jcore,cache"; | ||
58 | reg = <0xc0 4>; | ||
59 | }; | ||
60 | |||
61 | timer@200 { | ||
62 | compatible = "jcore,pit"; | ||
63 | reg = <0x200 0x30>; | ||
64 | interrupts = <0x48>; | ||
65 | }; | ||
66 | |||
67 | spi0: spi@40 { | ||
68 | compatible = "jcore,spi2"; | ||
69 | |||
70 | #address-cells = <1>; | ||
71 | #size-cells = <0>; | ||
72 | |||
73 | spi-max-frequency = <25000000>; | ||
74 | |||
75 | reg = <0x40 0x8>; | ||
76 | |||
77 | sdcard@0 { | ||
78 | compatible = "mmc-spi-slot"; | ||
79 | reg = <0>; | ||
80 | spi-max-frequency = <25000000>; | ||
81 | voltage-ranges = <3200 3400>; | ||
82 | mode = <0>; | ||
83 | }; | ||
84 | }; | ||
85 | |||
86 | uart0: serial@100 { | ||
87 | clock-frequency = <125000000>; | ||
88 | compatible = "xlnx,xps-uartlite-1.00.a"; | ||
89 | current-speed = <19200>; | ||
90 | device_type = "serial"; | ||
91 | interrupts = <0x12>; | ||
92 | port-number = <0>; | ||
93 | reg = <0x100 0x10>; | ||
94 | }; | ||
95 | }; | ||
96 | }; | ||
diff --git a/arch/sh/configs/j2_defconfig b/arch/sh/configs/j2_defconfig new file mode 100644 index 000000000000..94d1eca52f72 --- /dev/null +++ b/arch/sh/configs/j2_defconfig | |||
@@ -0,0 +1,40 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_SYSVIPC=y | ||
3 | CONFIG_POSIX_MQUEUE=y | ||
4 | CONFIG_NO_HZ=y | ||
5 | CONFIG_HIGH_RES_TIMERS=y | ||
6 | CONFIG_CPU_SUBTYPE_J2=y | ||
7 | CONFIG_MEMORY_START=0x10000000 | ||
8 | CONFIG_MEMORY_SIZE=0x04000000 | ||
9 | CONFIG_CPU_BIG_ENDIAN=y | ||
10 | CONFIG_SH_DEVICE_TREE=y | ||
11 | CONFIG_HZ_100=y | ||
12 | CONFIG_CMDLINE_OVERWRITE=y | ||
13 | CONFIG_CMDLINE="console=ttyUL0 earlycon" | ||
14 | CONFIG_BINFMT_ELF_FDPIC=y | ||
15 | CONFIG_BINFMT_FLAT=y | ||
16 | CONFIG_NET=y | ||
17 | CONFIG_PACKET=y | ||
18 | CONFIG_UNIX=y | ||
19 | CONFIG_INET=y | ||
20 | CONFIG_DEVTMPFS=y | ||
21 | CONFIG_DEVTMPFS_MOUNT=y | ||
22 | CONFIG_NETDEVICES=y | ||
23 | CONFIG_SERIAL_UARTLITE=y | ||
24 | CONFIG_SERIAL_UARTLITE_CONSOLE=y | ||
25 | CONFIG_I2C=y | ||
26 | CONFIG_SPI=y | ||
27 | CONFIG_SPI_JCORE=y | ||
28 | CONFIG_WATCHDOG=y | ||
29 | CONFIG_MMC=y | ||
30 | CONFIG_MMC_SPI=y | ||
31 | CONFIG_CLKSRC_JCORE_PIT=y | ||
32 | CONFIG_JCORE_AIC=y | ||
33 | CONFIG_EXT4_FS=y | ||
34 | CONFIG_VFAT_FS=y | ||
35 | CONFIG_FAT_DEFAULT_IOCHARSET="ascii" | ||
36 | CONFIG_FAT_DEFAULT_UTF8=y | ||
37 | CONFIG_NLS_DEFAULT="utf8" | ||
38 | CONFIG_NLS_CODEPAGE_437=y | ||
39 | CONFIG_NLS_ASCII=y | ||
40 | CONFIG_NLS_UTF8=y | ||
diff --git a/arch/sh/drivers/heartbeat.c b/arch/sh/drivers/heartbeat.c index 7efc9c354fc7..49bace446a1a 100644 --- a/arch/sh/drivers/heartbeat.c +++ b/arch/sh/drivers/heartbeat.c | |||
@@ -19,7 +19,6 @@ | |||
19 | * for more details. | 19 | * for more details. |
20 | */ | 20 | */ |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
24 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
25 | #include <linux/timer.h> | 24 | #include <linux/timer.h> |
@@ -139,26 +138,11 @@ static int heartbeat_drv_probe(struct platform_device *pdev) | |||
139 | return mod_timer(&hd->timer, jiffies + 1); | 138 | return mod_timer(&hd->timer, jiffies + 1); |
140 | } | 139 | } |
141 | 140 | ||
142 | static int heartbeat_drv_remove(struct platform_device *pdev) | ||
143 | { | ||
144 | struct heartbeat_data *hd = platform_get_drvdata(pdev); | ||
145 | |||
146 | del_timer_sync(&hd->timer); | ||
147 | iounmap(hd->base); | ||
148 | |||
149 | platform_set_drvdata(pdev, NULL); | ||
150 | |||
151 | if (!pdev->dev.platform_data) | ||
152 | kfree(hd); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static struct platform_driver heartbeat_driver = { | 141 | static struct platform_driver heartbeat_driver = { |
158 | .probe = heartbeat_drv_probe, | 142 | .probe = heartbeat_drv_probe, |
159 | .remove = heartbeat_drv_remove, | ||
160 | .driver = { | 143 | .driver = { |
161 | .name = DRV_NAME, | 144 | .name = DRV_NAME, |
145 | .suppress_bind_attrs = true, | ||
162 | }, | 146 | }, |
163 | }; | 147 | }; |
164 | 148 | ||
@@ -167,14 +151,4 @@ static int __init heartbeat_init(void) | |||
167 | printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION); | 151 | printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION); |
168 | return platform_driver_register(&heartbeat_driver); | 152 | return platform_driver_register(&heartbeat_driver); |
169 | } | 153 | } |
170 | 154 | device_initcall(heartbeat_init); | |
171 | static void __exit heartbeat_exit(void) | ||
172 | { | ||
173 | platform_driver_unregister(&heartbeat_driver); | ||
174 | } | ||
175 | module_init(heartbeat_init); | ||
176 | module_exit(heartbeat_exit); | ||
177 | |||
178 | MODULE_VERSION(DRV_VERSION); | ||
179 | MODULE_AUTHOR("Paul Mundt"); | ||
180 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index c399e1c55685..8a7bd80c8b33 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h | |||
@@ -1,6 +1,12 @@ | |||
1 | #ifndef __ASM_SH_ATOMIC_H | 1 | #ifndef __ASM_SH_ATOMIC_H |
2 | #define __ASM_SH_ATOMIC_H | 2 | #define __ASM_SH_ATOMIC_H |
3 | 3 | ||
4 | #if defined(CONFIG_CPU_J2) | ||
5 | |||
6 | #include <asm-generic/atomic.h> | ||
7 | |||
8 | #else | ||
9 | |||
4 | /* | 10 | /* |
5 | * Atomic operations that C can't guarantee us. Useful for | 11 | * Atomic operations that C can't guarantee us. Useful for |
6 | * resource counting etc.. | 12 | * resource counting etc.. |
@@ -63,4 +69,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
63 | return c; | 69 | return c; |
64 | } | 70 | } |
65 | 71 | ||
72 | #endif /* CONFIG_CPU_J2 */ | ||
73 | |||
66 | #endif /* __ASM_SH_ATOMIC_H */ | 74 | #endif /* __ASM_SH_ATOMIC_H */ |
diff --git a/arch/sh/include/asm/barrier.h b/arch/sh/include/asm/barrier.h index 8a84e05adb2e..3c30b6e166b6 100644 --- a/arch/sh/include/asm/barrier.h +++ b/arch/sh/include/asm/barrier.h | |||
@@ -29,6 +29,11 @@ | |||
29 | #define wmb() mb() | 29 | #define wmb() mb() |
30 | #define ctrl_barrier() __icbi(PAGE_OFFSET) | 30 | #define ctrl_barrier() __icbi(PAGE_OFFSET) |
31 | #else | 31 | #else |
32 | #if defined(CONFIG_CPU_J2) && defined(CONFIG_SMP) | ||
33 | #define __smp_mb() do { int tmp = 0; __asm__ __volatile__ ("cas.l %0,%0,@%1" : "+r"(tmp) : "z"(&tmp) : "memory", "t"); } while(0) | ||
34 | #define __smp_rmb() __smp_mb() | ||
35 | #define __smp_wmb() __smp_mb() | ||
36 | #endif | ||
32 | #define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop") | 37 | #define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop") |
33 | #endif | 38 | #endif |
34 | 39 | ||
diff --git a/arch/sh/include/asm/bitops-cas.h b/arch/sh/include/asm/bitops-cas.h new file mode 100644 index 000000000000..88f793c04d3c --- /dev/null +++ b/arch/sh/include/asm/bitops-cas.h | |||
@@ -0,0 +1,93 @@ | |||
1 | #ifndef __ASM_SH_BITOPS_CAS_H | ||
2 | #define __ASM_SH_BITOPS_CAS_H | ||
3 | |||
4 | static inline unsigned __bo_cas(volatile unsigned *p, unsigned old, unsigned new) | ||
5 | { | ||
6 | __asm__ __volatile__("cas.l %1,%0,@r0" | ||
7 | : "+r"(new) | ||
8 | : "r"(old), "z"(p) | ||
9 | : "t", "memory" ); | ||
10 | return new; | ||
11 | } | ||
12 | |||
13 | static inline void set_bit(int nr, volatile void *addr) | ||
14 | { | ||
15 | unsigned mask, old; | ||
16 | volatile unsigned *a = addr; | ||
17 | |||
18 | a += nr >> 5; | ||
19 | mask = 1U << (nr & 0x1f); | ||
20 | |||
21 | do old = *a; | ||
22 | while (__bo_cas(a, old, old|mask) != old); | ||
23 | } | ||
24 | |||
25 | static inline void clear_bit(int nr, volatile void *addr) | ||
26 | { | ||
27 | unsigned mask, old; | ||
28 | volatile unsigned *a = addr; | ||
29 | |||
30 | a += nr >> 5; | ||
31 | mask = 1U << (nr & 0x1f); | ||
32 | |||
33 | do old = *a; | ||
34 | while (__bo_cas(a, old, old&~mask) != old); | ||
35 | } | ||
36 | |||
37 | static inline void change_bit(int nr, volatile void *addr) | ||
38 | { | ||
39 | unsigned mask, old; | ||
40 | volatile unsigned *a = addr; | ||
41 | |||
42 | a += nr >> 5; | ||
43 | mask = 1U << (nr & 0x1f); | ||
44 | |||
45 | do old = *a; | ||
46 | while (__bo_cas(a, old, old^mask) != old); | ||
47 | } | ||
48 | |||
49 | static inline int test_and_set_bit(int nr, volatile void *addr) | ||
50 | { | ||
51 | unsigned mask, old; | ||
52 | volatile unsigned *a = addr; | ||
53 | |||
54 | a += nr >> 5; | ||
55 | mask = 1U << (nr & 0x1f); | ||
56 | |||
57 | do old = *a; | ||
58 | while (__bo_cas(a, old, old|mask) != old); | ||
59 | |||
60 | return !!(old & mask); | ||
61 | } | ||
62 | |||
63 | static inline int test_and_clear_bit(int nr, volatile void *addr) | ||
64 | { | ||
65 | unsigned mask, old; | ||
66 | volatile unsigned *a = addr; | ||
67 | |||
68 | a += nr >> 5; | ||
69 | mask = 1U << (nr & 0x1f); | ||
70 | |||
71 | do old = *a; | ||
72 | while (__bo_cas(a, old, old&~mask) != old); | ||
73 | |||
74 | return !!(old & mask); | ||
75 | } | ||
76 | |||
77 | static inline int test_and_change_bit(int nr, volatile void *addr) | ||
78 | { | ||
79 | unsigned mask, old; | ||
80 | volatile unsigned *a = addr; | ||
81 | |||
82 | a += nr >> 5; | ||
83 | mask = 1U << (nr & 0x1f); | ||
84 | |||
85 | do old = *a; | ||
86 | while (__bo_cas(a, old, old^mask) != old); | ||
87 | |||
88 | return !!(old & mask); | ||
89 | } | ||
90 | |||
91 | #include <asm-generic/bitops/non-atomic.h> | ||
92 | |||
93 | #endif /* __ASM_SH_BITOPS_CAS_H */ | ||
diff --git a/arch/sh/include/asm/bitops.h b/arch/sh/include/asm/bitops.h index fc8e652cf173..a8699d60a8c4 100644 --- a/arch/sh/include/asm/bitops.h +++ b/arch/sh/include/asm/bitops.h | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <asm/bitops-op32.h> | 18 | #include <asm/bitops-op32.h> |
19 | #elif defined(CONFIG_CPU_SH4A) | 19 | #elif defined(CONFIG_CPU_SH4A) |
20 | #include <asm/bitops-llsc.h> | 20 | #include <asm/bitops-llsc.h> |
21 | #elif defined(CONFIG_CPU_J2) && defined(CONFIG_SMP) | ||
22 | #include <asm/bitops-cas.h> | ||
21 | #else | 23 | #else |
22 | #include <asm-generic/bitops/atomic.h> | 24 | #include <asm-generic/bitops/atomic.h> |
23 | #include <asm-generic/bitops/non-atomic.h> | 25 | #include <asm-generic/bitops/non-atomic.h> |
diff --git a/arch/sh/include/asm/cmpxchg-cas.h b/arch/sh/include/asm/cmpxchg-cas.h new file mode 100644 index 000000000000..d0d86649e8c1 --- /dev/null +++ b/arch/sh/include/asm/cmpxchg-cas.h | |||
@@ -0,0 +1,24 @@ | |||
1 | #ifndef __ASM_SH_CMPXCHG_CAS_H | ||
2 | #define __ASM_SH_CMPXCHG_CAS_H | ||
3 | |||
4 | static inline unsigned long | ||
5 | __cmpxchg_u32(volatile u32 *m, unsigned long old, unsigned long new) | ||
6 | { | ||
7 | __asm__ __volatile__("cas.l %1,%0,@r0" | ||
8 | : "+r"(new) | ||
9 | : "r"(old), "z"(m) | ||
10 | : "t", "memory" ); | ||
11 | return new; | ||
12 | } | ||
13 | |||
14 | static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val) | ||
15 | { | ||
16 | unsigned long old; | ||
17 | do old = *m; | ||
18 | while (__cmpxchg_u32(m, old, val) != old); | ||
19 | return old; | ||
20 | } | ||
21 | |||
22 | #include <asm/cmpxchg-xchg.h> | ||
23 | |||
24 | #endif /* __ASM_SH_CMPXCHG_CAS_H */ | ||
diff --git a/arch/sh/include/asm/cmpxchg-xchg.h b/arch/sh/include/asm/cmpxchg-xchg.h index 7219719c23a3..1e881f5db659 100644 --- a/arch/sh/include/asm/cmpxchg-xchg.h +++ b/arch/sh/include/asm/cmpxchg-xchg.h | |||
@@ -21,7 +21,7 @@ static inline u32 __xchg_cmpxchg(volatile void *ptr, u32 x, int size) | |||
21 | int off = (unsigned long)ptr % sizeof(u32); | 21 | int off = (unsigned long)ptr % sizeof(u32); |
22 | volatile u32 *p = ptr - off; | 22 | volatile u32 *p = ptr - off; |
23 | #ifdef __BIG_ENDIAN | 23 | #ifdef __BIG_ENDIAN |
24 | int bitoff = (sizeof(u32) - 1 - off) * BITS_PER_BYTE; | 24 | int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE; |
25 | #else | 25 | #else |
26 | int bitoff = off * BITS_PER_BYTE; | 26 | int bitoff = off * BITS_PER_BYTE; |
27 | #endif | 27 | #endif |
diff --git a/arch/sh/include/asm/cmpxchg.h b/arch/sh/include/asm/cmpxchg.h index 5225916c1057..3dfe0467a773 100644 --- a/arch/sh/include/asm/cmpxchg.h +++ b/arch/sh/include/asm/cmpxchg.h | |||
@@ -13,6 +13,8 @@ | |||
13 | #include <asm/cmpxchg-grb.h> | 13 | #include <asm/cmpxchg-grb.h> |
14 | #elif defined(CONFIG_CPU_SH4A) | 14 | #elif defined(CONFIG_CPU_SH4A) |
15 | #include <asm/cmpxchg-llsc.h> | 15 | #include <asm/cmpxchg-llsc.h> |
16 | #elif defined(CONFIG_CPU_J2) && defined(CONFIG_SMP) | ||
17 | #include <asm/cmpxchg-cas.h> | ||
16 | #else | 18 | #else |
17 | #include <asm/cmpxchg-irq.h> | 19 | #include <asm/cmpxchg-irq.h> |
18 | #endif | 20 | #endif |
diff --git a/arch/sh/include/asm/futex-cas.h b/arch/sh/include/asm/futex-cas.h new file mode 100644 index 000000000000..267cb7a5f101 --- /dev/null +++ b/arch/sh/include/asm/futex-cas.h | |||
@@ -0,0 +1,34 @@ | |||
1 | #ifndef __ASM_SH_FUTEX_CAS_H | ||
2 | #define __ASM_SH_FUTEX_CAS_H | ||
3 | |||
4 | static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval, | ||
5 | u32 __user *uaddr, | ||
6 | u32 oldval, u32 newval) | ||
7 | { | ||
8 | int err = 0; | ||
9 | __asm__ __volatile__( | ||
10 | "1:\n\t" | ||
11 | "cas.l %2, %1, @r0\n" | ||
12 | "2:\n\t" | ||
13 | #ifdef CONFIG_MMU | ||
14 | ".section .fixup,\"ax\"\n" | ||
15 | "3:\n\t" | ||
16 | "mov.l 4f, %0\n\t" | ||
17 | "jmp @%0\n\t" | ||
18 | " mov %3, %0\n\t" | ||
19 | ".balign 4\n" | ||
20 | "4: .long 2b\n\t" | ||
21 | ".previous\n" | ||
22 | ".section __ex_table,\"a\"\n\t" | ||
23 | ".long 1b, 3b\n\t" | ||
24 | ".previous" | ||
25 | #endif | ||
26 | :"+r" (err), "+r" (newval) | ||
27 | :"r" (oldval), "i" (-EFAULT), "z" (uaddr) | ||
28 | :"t", "memory"); | ||
29 | if (err) return err; | ||
30 | *uval = newval; | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | #endif /* __ASM_SH_FUTEX_CAS_H */ | ||
diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h index 63d33129ea23..ab01dbee0a82 100644 --- a/arch/sh/include/asm/futex-irq.h +++ b/arch/sh/include/asm/futex-irq.h | |||
@@ -1,92 +1,6 @@ | |||
1 | #ifndef __ASM_SH_FUTEX_IRQ_H | 1 | #ifndef __ASM_SH_FUTEX_IRQ_H |
2 | #define __ASM_SH_FUTEX_IRQ_H | 2 | #define __ASM_SH_FUTEX_IRQ_H |
3 | 3 | ||
4 | |||
5 | static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, | ||
6 | int *oldval) | ||
7 | { | ||
8 | unsigned long flags; | ||
9 | int ret; | ||
10 | |||
11 | local_irq_save(flags); | ||
12 | |||
13 | ret = get_user(*oldval, uaddr); | ||
14 | if (!ret) | ||
15 | ret = put_user(oparg, uaddr); | ||
16 | |||
17 | local_irq_restore(flags); | ||
18 | |||
19 | return ret; | ||
20 | } | ||
21 | |||
22 | static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, | ||
23 | int *oldval) | ||
24 | { | ||
25 | unsigned long flags; | ||
26 | int ret; | ||
27 | |||
28 | local_irq_save(flags); | ||
29 | |||
30 | ret = get_user(*oldval, uaddr); | ||
31 | if (!ret) | ||
32 | ret = put_user(*oldval + oparg, uaddr); | ||
33 | |||
34 | local_irq_restore(flags); | ||
35 | |||
36 | return ret; | ||
37 | } | ||
38 | |||
39 | static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, | ||
40 | int *oldval) | ||
41 | { | ||
42 | unsigned long flags; | ||
43 | int ret; | ||
44 | |||
45 | local_irq_save(flags); | ||
46 | |||
47 | ret = get_user(*oldval, uaddr); | ||
48 | if (!ret) | ||
49 | ret = put_user(*oldval | oparg, uaddr); | ||
50 | |||
51 | local_irq_restore(flags); | ||
52 | |||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, | ||
57 | int *oldval) | ||
58 | { | ||
59 | unsigned long flags; | ||
60 | int ret; | ||
61 | |||
62 | local_irq_save(flags); | ||
63 | |||
64 | ret = get_user(*oldval, uaddr); | ||
65 | if (!ret) | ||
66 | ret = put_user(*oldval & oparg, uaddr); | ||
67 | |||
68 | local_irq_restore(flags); | ||
69 | |||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, | ||
74 | int *oldval) | ||
75 | { | ||
76 | unsigned long flags; | ||
77 | int ret; | ||
78 | |||
79 | local_irq_save(flags); | ||
80 | |||
81 | ret = get_user(*oldval, uaddr); | ||
82 | if (!ret) | ||
83 | ret = put_user(*oldval ^ oparg, uaddr); | ||
84 | |||
85 | local_irq_restore(flags); | ||
86 | |||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval, | 4 | static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval, |
91 | u32 __user *uaddr, | 5 | u32 __user *uaddr, |
92 | u32 oldval, u32 newval) | 6 | u32 oldval, u32 newval) |
diff --git a/arch/sh/include/asm/futex-llsc.h b/arch/sh/include/asm/futex-llsc.h new file mode 100644 index 000000000000..23591703bec0 --- /dev/null +++ b/arch/sh/include/asm/futex-llsc.h | |||
@@ -0,0 +1,41 @@ | |||
1 | #ifndef __ASM_SH_FUTEX_LLSC_H | ||
2 | #define __ASM_SH_FUTEX_LLSC_H | ||
3 | |||
4 | static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval, | ||
5 | u32 __user *uaddr, | ||
6 | u32 oldval, u32 newval) | ||
7 | { | ||
8 | int err = 0; | ||
9 | __asm__ __volatile__( | ||
10 | "synco\n" | ||
11 | "1:\n\t" | ||
12 | "movli.l @%2, r0\n\t" | ||
13 | "mov r0, %1\n\t" | ||
14 | "cmp/eq %1, %4\n\t" | ||
15 | "bf 2f\n\t" | ||
16 | "mov %5, r0\n\t" | ||
17 | "movco.l r0, @%2\n\t" | ||
18 | "bf 1b\n" | ||
19 | "2:\n\t" | ||
20 | "synco\n\t" | ||
21 | #ifdef CONFIG_MMU | ||
22 | ".section .fixup,\"ax\"\n" | ||
23 | "3:\n\t" | ||
24 | "mov.l 4f, %0\n\t" | ||
25 | "jmp @%0\n\t" | ||
26 | " mov %3, %0\n\t" | ||
27 | ".balign 4\n" | ||
28 | "4: .long 2b\n\t" | ||
29 | ".previous\n" | ||
30 | ".section __ex_table,\"a\"\n\t" | ||
31 | ".long 1b, 3b\n\t" | ||
32 | ".previous" | ||
33 | #endif | ||
34 | :"+r" (err), "=&r" (*uval) | ||
35 | :"r" (uaddr), "i" (-EFAULT), "r" (oldval), "r" (newval) | ||
36 | :"t", "memory", "r0"); | ||
37 | if (err) return err; | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | #endif /* __ASM_SH_FUTEX_LLSC_H */ | ||
diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h index 7be39a646fbd..d0078747d308 100644 --- a/arch/sh/include/asm/futex.h +++ b/arch/sh/include/asm/futex.h | |||
@@ -7,16 +7,34 @@ | |||
7 | #include <linux/uaccess.h> | 7 | #include <linux/uaccess.h> |
8 | #include <asm/errno.h> | 8 | #include <asm/errno.h> |
9 | 9 | ||
10 | /* XXX: UP variants, fix for SH-4A and SMP.. */ | 10 | #if !defined(CONFIG_SMP) |
11 | #include <asm/futex-irq.h> | 11 | #include <asm/futex-irq.h> |
12 | #elif defined(CONFIG_CPU_J2) | ||
13 | #include <asm/futex-cas.h> | ||
14 | #elif defined(CONFIG_CPU_SH4A) | ||
15 | #include <asm/futex-llsc.h> | ||
16 | #else | ||
17 | #error SMP not supported on this configuration. | ||
18 | #endif | ||
19 | |||
20 | static inline int | ||
21 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | ||
22 | u32 oldval, u32 newval) | ||
23 | { | ||
24 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | ||
25 | return -EFAULT; | ||
26 | |||
27 | return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval); | ||
28 | } | ||
12 | 29 | ||
13 | static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | 30 | static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) |
14 | { | 31 | { |
15 | int op = (encoded_op >> 28) & 7; | 32 | int op = (encoded_op >> 28) & 7; |
16 | int cmp = (encoded_op >> 24) & 15; | 33 | int cmp = (encoded_op >> 24) & 15; |
17 | int oparg = (encoded_op << 8) >> 20; | 34 | u32 oparg = (encoded_op << 8) >> 20; |
18 | int cmparg = (encoded_op << 20) >> 20; | 35 | u32 cmparg = (encoded_op << 20) >> 20; |
19 | int oldval = 0, ret; | 36 | u32 oldval, newval, prev; |
37 | int ret; | ||
20 | 38 | ||
21 | if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | 39 | if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) |
22 | oparg = 1 << oparg; | 40 | oparg = 1 << oparg; |
@@ -26,26 +44,39 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |||
26 | 44 | ||
27 | pagefault_disable(); | 45 | pagefault_disable(); |
28 | 46 | ||
29 | switch (op) { | 47 | do { |
30 | case FUTEX_OP_SET: | 48 | if (op == FUTEX_OP_SET) |
31 | ret = atomic_futex_op_xchg_set(oparg, uaddr, &oldval); | 49 | ret = oldval = 0; |
32 | break; | 50 | else |
33 | case FUTEX_OP_ADD: | 51 | ret = get_user(oldval, uaddr); |
34 | ret = atomic_futex_op_xchg_add(oparg, uaddr, &oldval); | 52 | |
35 | break; | 53 | if (ret) break; |
36 | case FUTEX_OP_OR: | 54 | |
37 | ret = atomic_futex_op_xchg_or(oparg, uaddr, &oldval); | 55 | switch (op) { |
38 | break; | 56 | case FUTEX_OP_SET: |
39 | case FUTEX_OP_ANDN: | 57 | newval = oparg; |
40 | ret = atomic_futex_op_xchg_and(~oparg, uaddr, &oldval); | 58 | break; |
41 | break; | 59 | case FUTEX_OP_ADD: |
42 | case FUTEX_OP_XOR: | 60 | newval = oldval + oparg; |
43 | ret = atomic_futex_op_xchg_xor(oparg, uaddr, &oldval); | 61 | break; |
44 | break; | 62 | case FUTEX_OP_OR: |
45 | default: | 63 | newval = oldval | oparg; |
46 | ret = -ENOSYS; | 64 | break; |
47 | break; | 65 | case FUTEX_OP_ANDN: |
48 | } | 66 | newval = oldval & ~oparg; |
67 | break; | ||
68 | case FUTEX_OP_XOR: | ||
69 | newval = oldval ^ oparg; | ||
70 | break; | ||
71 | default: | ||
72 | ret = -ENOSYS; | ||
73 | break; | ||
74 | } | ||
75 | |||
76 | if (ret) break; | ||
77 | |||
78 | ret = futex_atomic_cmpxchg_inatomic(&prev, uaddr, oldval, newval); | ||
79 | } while (!ret && prev != oldval); | ||
49 | 80 | ||
50 | pagefault_enable(); | 81 | pagefault_enable(); |
51 | 82 | ||
@@ -53,10 +84,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |||
53 | switch (cmp) { | 84 | switch (cmp) { |
54 | case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | 85 | case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; |
55 | case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | 86 | case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; |
56 | case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | 87 | case FUTEX_OP_CMP_LT: ret = ((int)oldval < (int)cmparg); break; |
57 | case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | 88 | case FUTEX_OP_CMP_GE: ret = ((int)oldval >= (int)cmparg); break; |
58 | case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | 89 | case FUTEX_OP_CMP_LE: ret = ((int)oldval <= (int)cmparg); break; |
59 | case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | 90 | case FUTEX_OP_CMP_GT: ret = ((int)oldval > (int)cmparg); break; |
60 | default: ret = -ENOSYS; | 91 | default: ret = -ENOSYS; |
61 | } | 92 | } |
62 | } | 93 | } |
@@ -64,15 +95,5 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | |||
64 | return ret; | 95 | return ret; |
65 | } | 96 | } |
66 | 97 | ||
67 | static inline int | ||
68 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | ||
69 | u32 oldval, u32 newval) | ||
70 | { | ||
71 | if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) | ||
72 | return -EFAULT; | ||
73 | |||
74 | return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval); | ||
75 | } | ||
76 | |||
77 | #endif /* __KERNEL__ */ | 98 | #endif /* __KERNEL__ */ |
78 | #endif /* __ASM_SH_FUTEX_H */ | 99 | #endif /* __ASM_SH_FUTEX_H */ |
diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h index 1506897648aa..f9a09942a32d 100644 --- a/arch/sh/include/asm/processor.h +++ b/arch/sh/include/asm/processor.h | |||
@@ -15,7 +15,7 @@ | |||
15 | */ | 15 | */ |
16 | enum cpu_type { | 16 | enum cpu_type { |
17 | /* SH-2 types */ | 17 | /* SH-2 types */ |
18 | CPU_SH7619, | 18 | CPU_SH7619, CPU_J2, |
19 | 19 | ||
20 | /* SH-2A types */ | 20 | /* SH-2A types */ |
21 | CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_SH7264, CPU_SH7269, | 21 | CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_SH7264, CPU_SH7269, |
diff --git a/arch/sh/include/asm/spinlock-cas.h b/arch/sh/include/asm/spinlock-cas.h new file mode 100644 index 000000000000..c46e8cc7b515 --- /dev/null +++ b/arch/sh/include/asm/spinlock-cas.h | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * include/asm-sh/spinlock-cas.h | ||
3 | * | ||
4 | * Copyright (C) 2015 SEI | ||
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 | #ifndef __ASM_SH_SPINLOCK_CAS_H | ||
11 | #define __ASM_SH_SPINLOCK_CAS_H | ||
12 | |||
13 | #include <asm/barrier.h> | ||
14 | #include <asm/processor.h> | ||
15 | |||
16 | static inline unsigned __sl_cas(volatile unsigned *p, unsigned old, unsigned new) | ||
17 | { | ||
18 | __asm__ __volatile__("cas.l %1,%0,@r0" | ||
19 | : "+r"(new) | ||
20 | : "r"(old), "z"(p) | ||
21 | : "t", "memory" ); | ||
22 | return new; | ||
23 | } | ||
24 | |||
25 | /* | ||
26 | * Your basic SMP spinlocks, allowing only a single CPU anywhere | ||
27 | */ | ||
28 | |||
29 | #define arch_spin_is_locked(x) ((x)->lock <= 0) | ||
30 | #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) | ||
31 | |||
32 | static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) | ||
33 | { | ||
34 | smp_cond_load_acquire(&lock->lock, VAL > 0); | ||
35 | } | ||
36 | |||
37 | static inline void arch_spin_lock(arch_spinlock_t *lock) | ||
38 | { | ||
39 | while (!__sl_cas(&lock->lock, 1, 0)); | ||
40 | } | ||
41 | |||
42 | static inline void arch_spin_unlock(arch_spinlock_t *lock) | ||
43 | { | ||
44 | __sl_cas(&lock->lock, 0, 1); | ||
45 | } | ||
46 | |||
47 | static inline int arch_spin_trylock(arch_spinlock_t *lock) | ||
48 | { | ||
49 | return __sl_cas(&lock->lock, 1, 0); | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | * Read-write spinlocks, allowing multiple readers but only one writer. | ||
54 | * | ||
55 | * NOTE! it is quite common to have readers in interrupts but no interrupt | ||
56 | * writers. For those circumstances we can "mix" irq-safe locks - any writer | ||
57 | * needs to get a irq-safe write-lock, but readers can get non-irqsafe | ||
58 | * read-locks. | ||
59 | */ | ||
60 | |||
61 | /** | ||
62 | * read_can_lock - would read_trylock() succeed? | ||
63 | * @lock: the rwlock in question. | ||
64 | */ | ||
65 | #define arch_read_can_lock(x) ((x)->lock > 0) | ||
66 | |||
67 | /** | ||
68 | * write_can_lock - would write_trylock() succeed? | ||
69 | * @lock: the rwlock in question. | ||
70 | */ | ||
71 | #define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) | ||
72 | |||
73 | static inline void arch_read_lock(arch_rwlock_t *rw) | ||
74 | { | ||
75 | unsigned old; | ||
76 | do old = rw->lock; | ||
77 | while (!old || __sl_cas(&rw->lock, old, old-1) != old); | ||
78 | } | ||
79 | |||
80 | static inline void arch_read_unlock(arch_rwlock_t *rw) | ||
81 | { | ||
82 | unsigned old; | ||
83 | do old = rw->lock; | ||
84 | while (__sl_cas(&rw->lock, old, old+1) != old); | ||
85 | } | ||
86 | |||
87 | static inline void arch_write_lock(arch_rwlock_t *rw) | ||
88 | { | ||
89 | while (__sl_cas(&rw->lock, RW_LOCK_BIAS, 0) != RW_LOCK_BIAS); | ||
90 | } | ||
91 | |||
92 | static inline void arch_write_unlock(arch_rwlock_t *rw) | ||
93 | { | ||
94 | __sl_cas(&rw->lock, 0, RW_LOCK_BIAS); | ||
95 | } | ||
96 | |||
97 | static inline int arch_read_trylock(arch_rwlock_t *rw) | ||
98 | { | ||
99 | unsigned old; | ||
100 | do old = rw->lock; | ||
101 | while (old && __sl_cas(&rw->lock, old, old-1) != old); | ||
102 | return !!old; | ||
103 | } | ||
104 | |||
105 | static inline int arch_write_trylock(arch_rwlock_t *rw) | ||
106 | { | ||
107 | return __sl_cas(&rw->lock, RW_LOCK_BIAS, 0) == RW_LOCK_BIAS; | ||
108 | } | ||
109 | |||
110 | #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) | ||
111 | #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) | ||
112 | |||
113 | #define arch_spin_relax(lock) cpu_relax() | ||
114 | #define arch_read_relax(lock) cpu_relax() | ||
115 | #define arch_write_relax(lock) cpu_relax() | ||
116 | |||
117 | #endif /* __ASM_SH_SPINLOCK_CAS_H */ | ||
diff --git a/arch/sh/include/asm/spinlock-llsc.h b/arch/sh/include/asm/spinlock-llsc.h new file mode 100644 index 000000000000..cec78143fa83 --- /dev/null +++ b/arch/sh/include/asm/spinlock-llsc.h | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * include/asm-sh/spinlock-llsc.h | ||
3 | * | ||
4 | * Copyright (C) 2002, 2003 Paul Mundt | ||
5 | * Copyright (C) 2006, 2007 Akio Idehara | ||
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 | #ifndef __ASM_SH_SPINLOCK_LLSC_H | ||
12 | #define __ASM_SH_SPINLOCK_LLSC_H | ||
13 | |||
14 | #include <asm/barrier.h> | ||
15 | #include <asm/processor.h> | ||
16 | |||
17 | /* | ||
18 | * Your basic SMP spinlocks, allowing only a single CPU anywhere | ||
19 | */ | ||
20 | |||
21 | #define arch_spin_is_locked(x) ((x)->lock <= 0) | ||
22 | #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) | ||
23 | |||
24 | static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) | ||
25 | { | ||
26 | smp_cond_load_acquire(&lock->lock, VAL > 0); | ||
27 | } | ||
28 | |||
29 | /* | ||
30 | * Simple spin lock operations. There are two variants, one clears IRQ's | ||
31 | * on the local processor, one does not. | ||
32 | * | ||
33 | * We make no fairness assumptions. They have a cost. | ||
34 | */ | ||
35 | static inline void arch_spin_lock(arch_spinlock_t *lock) | ||
36 | { | ||
37 | unsigned long tmp; | ||
38 | unsigned long oldval; | ||
39 | |||
40 | __asm__ __volatile__ ( | ||
41 | "1: \n\t" | ||
42 | "movli.l @%2, %0 ! arch_spin_lock \n\t" | ||
43 | "mov %0, %1 \n\t" | ||
44 | "mov #0, %0 \n\t" | ||
45 | "movco.l %0, @%2 \n\t" | ||
46 | "bf 1b \n\t" | ||
47 | "cmp/pl %1 \n\t" | ||
48 | "bf 1b \n\t" | ||
49 | : "=&z" (tmp), "=&r" (oldval) | ||
50 | : "r" (&lock->lock) | ||
51 | : "t", "memory" | ||
52 | ); | ||
53 | } | ||
54 | |||
55 | static inline void arch_spin_unlock(arch_spinlock_t *lock) | ||
56 | { | ||
57 | unsigned long tmp; | ||
58 | |||
59 | __asm__ __volatile__ ( | ||
60 | "mov #1, %0 ! arch_spin_unlock \n\t" | ||
61 | "mov.l %0, @%1 \n\t" | ||
62 | : "=&z" (tmp) | ||
63 | : "r" (&lock->lock) | ||
64 | : "t", "memory" | ||
65 | ); | ||
66 | } | ||
67 | |||
68 | static inline int arch_spin_trylock(arch_spinlock_t *lock) | ||
69 | { | ||
70 | unsigned long tmp, oldval; | ||
71 | |||
72 | __asm__ __volatile__ ( | ||
73 | "1: \n\t" | ||
74 | "movli.l @%2, %0 ! arch_spin_trylock \n\t" | ||
75 | "mov %0, %1 \n\t" | ||
76 | "mov #0, %0 \n\t" | ||
77 | "movco.l %0, @%2 \n\t" | ||
78 | "bf 1b \n\t" | ||
79 | "synco \n\t" | ||
80 | : "=&z" (tmp), "=&r" (oldval) | ||
81 | : "r" (&lock->lock) | ||
82 | : "t", "memory" | ||
83 | ); | ||
84 | |||
85 | return oldval; | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * Read-write spinlocks, allowing multiple readers but only one writer. | ||
90 | * | ||
91 | * NOTE! it is quite common to have readers in interrupts but no interrupt | ||
92 | * writers. For those circumstances we can "mix" irq-safe locks - any writer | ||
93 | * needs to get a irq-safe write-lock, but readers can get non-irqsafe | ||
94 | * read-locks. | ||
95 | */ | ||
96 | |||
97 | /** | ||
98 | * read_can_lock - would read_trylock() succeed? | ||
99 | * @lock: the rwlock in question. | ||
100 | */ | ||
101 | #define arch_read_can_lock(x) ((x)->lock > 0) | ||
102 | |||
103 | /** | ||
104 | * write_can_lock - would write_trylock() succeed? | ||
105 | * @lock: the rwlock in question. | ||
106 | */ | ||
107 | #define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) | ||
108 | |||
109 | static inline void arch_read_lock(arch_rwlock_t *rw) | ||
110 | { | ||
111 | unsigned long tmp; | ||
112 | |||
113 | __asm__ __volatile__ ( | ||
114 | "1: \n\t" | ||
115 | "movli.l @%1, %0 ! arch_read_lock \n\t" | ||
116 | "cmp/pl %0 \n\t" | ||
117 | "bf 1b \n\t" | ||
118 | "add #-1, %0 \n\t" | ||
119 | "movco.l %0, @%1 \n\t" | ||
120 | "bf 1b \n\t" | ||
121 | : "=&z" (tmp) | ||
122 | : "r" (&rw->lock) | ||
123 | : "t", "memory" | ||
124 | ); | ||
125 | } | ||
126 | |||
127 | static inline void arch_read_unlock(arch_rwlock_t *rw) | ||
128 | { | ||
129 | unsigned long tmp; | ||
130 | |||
131 | __asm__ __volatile__ ( | ||
132 | "1: \n\t" | ||
133 | "movli.l @%1, %0 ! arch_read_unlock \n\t" | ||
134 | "add #1, %0 \n\t" | ||
135 | "movco.l %0, @%1 \n\t" | ||
136 | "bf 1b \n\t" | ||
137 | : "=&z" (tmp) | ||
138 | : "r" (&rw->lock) | ||
139 | : "t", "memory" | ||
140 | ); | ||
141 | } | ||
142 | |||
143 | static inline void arch_write_lock(arch_rwlock_t *rw) | ||
144 | { | ||
145 | unsigned long tmp; | ||
146 | |||
147 | __asm__ __volatile__ ( | ||
148 | "1: \n\t" | ||
149 | "movli.l @%1, %0 ! arch_write_lock \n\t" | ||
150 | "cmp/hs %2, %0 \n\t" | ||
151 | "bf 1b \n\t" | ||
152 | "sub %2, %0 \n\t" | ||
153 | "movco.l %0, @%1 \n\t" | ||
154 | "bf 1b \n\t" | ||
155 | : "=&z" (tmp) | ||
156 | : "r" (&rw->lock), "r" (RW_LOCK_BIAS) | ||
157 | : "t", "memory" | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | static inline void arch_write_unlock(arch_rwlock_t *rw) | ||
162 | { | ||
163 | __asm__ __volatile__ ( | ||
164 | "mov.l %1, @%0 ! arch_write_unlock \n\t" | ||
165 | : | ||
166 | : "r" (&rw->lock), "r" (RW_LOCK_BIAS) | ||
167 | : "t", "memory" | ||
168 | ); | ||
169 | } | ||
170 | |||
171 | static inline int arch_read_trylock(arch_rwlock_t *rw) | ||
172 | { | ||
173 | unsigned long tmp, oldval; | ||
174 | |||
175 | __asm__ __volatile__ ( | ||
176 | "1: \n\t" | ||
177 | "movli.l @%2, %0 ! arch_read_trylock \n\t" | ||
178 | "mov %0, %1 \n\t" | ||
179 | "cmp/pl %0 \n\t" | ||
180 | "bf 2f \n\t" | ||
181 | "add #-1, %0 \n\t" | ||
182 | "movco.l %0, @%2 \n\t" | ||
183 | "bf 1b \n\t" | ||
184 | "2: \n\t" | ||
185 | "synco \n\t" | ||
186 | : "=&z" (tmp), "=&r" (oldval) | ||
187 | : "r" (&rw->lock) | ||
188 | : "t", "memory" | ||
189 | ); | ||
190 | |||
191 | return (oldval > 0); | ||
192 | } | ||
193 | |||
194 | static inline int arch_write_trylock(arch_rwlock_t *rw) | ||
195 | { | ||
196 | unsigned long tmp, oldval; | ||
197 | |||
198 | __asm__ __volatile__ ( | ||
199 | "1: \n\t" | ||
200 | "movli.l @%2, %0 ! arch_write_trylock \n\t" | ||
201 | "mov %0, %1 \n\t" | ||
202 | "cmp/hs %3, %0 \n\t" | ||
203 | "bf 2f \n\t" | ||
204 | "sub %3, %0 \n\t" | ||
205 | "2: \n\t" | ||
206 | "movco.l %0, @%2 \n\t" | ||
207 | "bf 1b \n\t" | ||
208 | "synco \n\t" | ||
209 | : "=&z" (tmp), "=&r" (oldval) | ||
210 | : "r" (&rw->lock), "r" (RW_LOCK_BIAS) | ||
211 | : "t", "memory" | ||
212 | ); | ||
213 | |||
214 | return (oldval > (RW_LOCK_BIAS - 1)); | ||
215 | } | ||
216 | |||
217 | #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) | ||
218 | #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) | ||
219 | |||
220 | #define arch_spin_relax(lock) cpu_relax() | ||
221 | #define arch_read_relax(lock) cpu_relax() | ||
222 | #define arch_write_relax(lock) cpu_relax() | ||
223 | |||
224 | #endif /* __ASM_SH_SPINLOCK_LLSC_H */ | ||
diff --git a/arch/sh/include/asm/spinlock.h b/arch/sh/include/asm/spinlock.h index 416834b60ad0..c2c61ea6a8e2 100644 --- a/arch/sh/include/asm/spinlock.h +++ b/arch/sh/include/asm/spinlock.h | |||
@@ -11,222 +11,12 @@ | |||
11 | #ifndef __ASM_SH_SPINLOCK_H | 11 | #ifndef __ASM_SH_SPINLOCK_H |
12 | #define __ASM_SH_SPINLOCK_H | 12 | #define __ASM_SH_SPINLOCK_H |
13 | 13 | ||
14 | /* | 14 | #if defined(CONFIG_CPU_SH4A) |
15 | * The only locking implemented here uses SH-4A opcodes. For others, | 15 | #include <asm/spinlock-llsc.h> |
16 | * split this out as per atomic-*.h. | 16 | #elif defined(CONFIG_CPU_J2) |
17 | */ | 17 | #include <asm/spinlock-cas.h> |
18 | #ifndef CONFIG_CPU_SH4A | 18 | #else |
19 | #error "Need movli.l/movco.l for spinlocks" | 19 | #error "The configured cpu type does not support spinlocks" |
20 | #endif | 20 | #endif |
21 | 21 | ||
22 | #include <asm/barrier.h> | ||
23 | #include <asm/processor.h> | ||
24 | |||
25 | /* | ||
26 | * Your basic SMP spinlocks, allowing only a single CPU anywhere | ||
27 | */ | ||
28 | |||
29 | #define arch_spin_is_locked(x) ((x)->lock <= 0) | ||
30 | #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) | ||
31 | |||
32 | static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) | ||
33 | { | ||
34 | smp_cond_load_acquire(&lock->lock, VAL > 0); | ||
35 | } | ||
36 | |||
37 | /* | ||
38 | * Simple spin lock operations. There are two variants, one clears IRQ's | ||
39 | * on the local processor, one does not. | ||
40 | * | ||
41 | * We make no fairness assumptions. They have a cost. | ||
42 | */ | ||
43 | static inline void arch_spin_lock(arch_spinlock_t *lock) | ||
44 | { | ||
45 | unsigned long tmp; | ||
46 | unsigned long oldval; | ||
47 | |||
48 | __asm__ __volatile__ ( | ||
49 | "1: \n\t" | ||
50 | "movli.l @%2, %0 ! arch_spin_lock \n\t" | ||
51 | "mov %0, %1 \n\t" | ||
52 | "mov #0, %0 \n\t" | ||
53 | "movco.l %0, @%2 \n\t" | ||
54 | "bf 1b \n\t" | ||
55 | "cmp/pl %1 \n\t" | ||
56 | "bf 1b \n\t" | ||
57 | : "=&z" (tmp), "=&r" (oldval) | ||
58 | : "r" (&lock->lock) | ||
59 | : "t", "memory" | ||
60 | ); | ||
61 | } | ||
62 | |||
63 | static inline void arch_spin_unlock(arch_spinlock_t *lock) | ||
64 | { | ||
65 | unsigned long tmp; | ||
66 | |||
67 | __asm__ __volatile__ ( | ||
68 | "mov #1, %0 ! arch_spin_unlock \n\t" | ||
69 | "mov.l %0, @%1 \n\t" | ||
70 | : "=&z" (tmp) | ||
71 | : "r" (&lock->lock) | ||
72 | : "t", "memory" | ||
73 | ); | ||
74 | } | ||
75 | |||
76 | static inline int arch_spin_trylock(arch_spinlock_t *lock) | ||
77 | { | ||
78 | unsigned long tmp, oldval; | ||
79 | |||
80 | __asm__ __volatile__ ( | ||
81 | "1: \n\t" | ||
82 | "movli.l @%2, %0 ! arch_spin_trylock \n\t" | ||
83 | "mov %0, %1 \n\t" | ||
84 | "mov #0, %0 \n\t" | ||
85 | "movco.l %0, @%2 \n\t" | ||
86 | "bf 1b \n\t" | ||
87 | "synco \n\t" | ||
88 | : "=&z" (tmp), "=&r" (oldval) | ||
89 | : "r" (&lock->lock) | ||
90 | : "t", "memory" | ||
91 | ); | ||
92 | |||
93 | return oldval; | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Read-write spinlocks, allowing multiple readers but only one writer. | ||
98 | * | ||
99 | * NOTE! it is quite common to have readers in interrupts but no interrupt | ||
100 | * writers. For those circumstances we can "mix" irq-safe locks - any writer | ||
101 | * needs to get a irq-safe write-lock, but readers can get non-irqsafe | ||
102 | * read-locks. | ||
103 | */ | ||
104 | |||
105 | /** | ||
106 | * read_can_lock - would read_trylock() succeed? | ||
107 | * @lock: the rwlock in question. | ||
108 | */ | ||
109 | #define arch_read_can_lock(x) ((x)->lock > 0) | ||
110 | |||
111 | /** | ||
112 | * write_can_lock - would write_trylock() succeed? | ||
113 | * @lock: the rwlock in question. | ||
114 | */ | ||
115 | #define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) | ||
116 | |||
117 | static inline void arch_read_lock(arch_rwlock_t *rw) | ||
118 | { | ||
119 | unsigned long tmp; | ||
120 | |||
121 | __asm__ __volatile__ ( | ||
122 | "1: \n\t" | ||
123 | "movli.l @%1, %0 ! arch_read_lock \n\t" | ||
124 | "cmp/pl %0 \n\t" | ||
125 | "bf 1b \n\t" | ||
126 | "add #-1, %0 \n\t" | ||
127 | "movco.l %0, @%1 \n\t" | ||
128 | "bf 1b \n\t" | ||
129 | : "=&z" (tmp) | ||
130 | : "r" (&rw->lock) | ||
131 | : "t", "memory" | ||
132 | ); | ||
133 | } | ||
134 | |||
135 | static inline void arch_read_unlock(arch_rwlock_t *rw) | ||
136 | { | ||
137 | unsigned long tmp; | ||
138 | |||
139 | __asm__ __volatile__ ( | ||
140 | "1: \n\t" | ||
141 | "movli.l @%1, %0 ! arch_read_unlock \n\t" | ||
142 | "add #1, %0 \n\t" | ||
143 | "movco.l %0, @%1 \n\t" | ||
144 | "bf 1b \n\t" | ||
145 | : "=&z" (tmp) | ||
146 | : "r" (&rw->lock) | ||
147 | : "t", "memory" | ||
148 | ); | ||
149 | } | ||
150 | |||
151 | static inline void arch_write_lock(arch_rwlock_t *rw) | ||
152 | { | ||
153 | unsigned long tmp; | ||
154 | |||
155 | __asm__ __volatile__ ( | ||
156 | "1: \n\t" | ||
157 | "movli.l @%1, %0 ! arch_write_lock \n\t" | ||
158 | "cmp/hs %2, %0 \n\t" | ||
159 | "bf 1b \n\t" | ||
160 | "sub %2, %0 \n\t" | ||
161 | "movco.l %0, @%1 \n\t" | ||
162 | "bf 1b \n\t" | ||
163 | : "=&z" (tmp) | ||
164 | : "r" (&rw->lock), "r" (RW_LOCK_BIAS) | ||
165 | : "t", "memory" | ||
166 | ); | ||
167 | } | ||
168 | |||
169 | static inline void arch_write_unlock(arch_rwlock_t *rw) | ||
170 | { | ||
171 | __asm__ __volatile__ ( | ||
172 | "mov.l %1, @%0 ! arch_write_unlock \n\t" | ||
173 | : | ||
174 | : "r" (&rw->lock), "r" (RW_LOCK_BIAS) | ||
175 | : "t", "memory" | ||
176 | ); | ||
177 | } | ||
178 | |||
179 | static inline int arch_read_trylock(arch_rwlock_t *rw) | ||
180 | { | ||
181 | unsigned long tmp, oldval; | ||
182 | |||
183 | __asm__ __volatile__ ( | ||
184 | "1: \n\t" | ||
185 | "movli.l @%2, %0 ! arch_read_trylock \n\t" | ||
186 | "mov %0, %1 \n\t" | ||
187 | "cmp/pl %0 \n\t" | ||
188 | "bf 2f \n\t" | ||
189 | "add #-1, %0 \n\t" | ||
190 | "movco.l %0, @%2 \n\t" | ||
191 | "bf 1b \n\t" | ||
192 | "2: \n\t" | ||
193 | "synco \n\t" | ||
194 | : "=&z" (tmp), "=&r" (oldval) | ||
195 | : "r" (&rw->lock) | ||
196 | : "t", "memory" | ||
197 | ); | ||
198 | |||
199 | return (oldval > 0); | ||
200 | } | ||
201 | |||
202 | static inline int arch_write_trylock(arch_rwlock_t *rw) | ||
203 | { | ||
204 | unsigned long tmp, oldval; | ||
205 | |||
206 | __asm__ __volatile__ ( | ||
207 | "1: \n\t" | ||
208 | "movli.l @%2, %0 ! arch_write_trylock \n\t" | ||
209 | "mov %0, %1 \n\t" | ||
210 | "cmp/hs %3, %0 \n\t" | ||
211 | "bf 2f \n\t" | ||
212 | "sub %3, %0 \n\t" | ||
213 | "2: \n\t" | ||
214 | "movco.l %0, @%2 \n\t" | ||
215 | "bf 1b \n\t" | ||
216 | "synco \n\t" | ||
217 | : "=&z" (tmp), "=&r" (oldval) | ||
218 | : "r" (&rw->lock), "r" (RW_LOCK_BIAS) | ||
219 | : "t", "memory" | ||
220 | ); | ||
221 | |||
222 | return (oldval > (RW_LOCK_BIAS - 1)); | ||
223 | } | ||
224 | |||
225 | #define arch_read_lock_flags(lock, flags) arch_read_lock(lock) | ||
226 | #define arch_write_lock_flags(lock, flags) arch_write_lock(lock) | ||
227 | |||
228 | #define arch_spin_relax(lock) cpu_relax() | ||
229 | #define arch_read_relax(lock) cpu_relax() | ||
230 | #define arch_write_relax(lock) cpu_relax() | ||
231 | |||
232 | #endif /* __ASM_SH_SPINLOCK_H */ | 22 | #endif /* __ASM_SH_SPINLOCK_H */ |
diff --git a/arch/sh/include/uapi/asm/cpu-features.h b/arch/sh/include/uapi/asm/cpu-features.h index 694abe490edb..2f1bc851042a 100644 --- a/arch/sh/include/uapi/asm/cpu-features.h +++ b/arch/sh/include/uapi/asm/cpu-features.h | |||
@@ -22,5 +22,6 @@ | |||
22 | #define CPU_HAS_L2_CACHE 0x0080 /* Secondary cache / URAM */ | 22 | #define CPU_HAS_L2_CACHE 0x0080 /* Secondary cache / URAM */ |
23 | #define CPU_HAS_OP32 0x0100 /* 32-bit instruction support */ | 23 | #define CPU_HAS_OP32 0x0100 /* 32-bit instruction support */ |
24 | #define CPU_HAS_PTEAEX 0x0200 /* PTE ASID Extension support */ | 24 | #define CPU_HAS_PTEAEX 0x0200 /* PTE ASID Extension support */ |
25 | #define CPU_HAS_CAS_L 0x0400 /* cas.l atomic compare-and-swap */ | ||
25 | 26 | ||
26 | #endif /* __ASM_SH_CPU_FEATURES_H */ | 27 | #endif /* __ASM_SH_CPU_FEATURES_H */ |
diff --git a/arch/sh/include/uapi/asm/sigcontext.h b/arch/sh/include/uapi/asm/sigcontext.h index 8ce1435bc0bf..faa5d0833412 100644 --- a/arch/sh/include/uapi/asm/sigcontext.h +++ b/arch/sh/include/uapi/asm/sigcontext.h | |||
@@ -25,8 +25,6 @@ struct sigcontext { | |||
25 | unsigned long sc_mach; | 25 | unsigned long sc_mach; |
26 | unsigned long sc_macl; | 26 | unsigned long sc_macl; |
27 | 27 | ||
28 | #if defined(__SH4__) || defined(CONFIG_CPU_SH4) || \ | ||
29 | defined(__SH2A__) || defined(CONFIG_CPU_SH2A) | ||
30 | /* FPU registers */ | 28 | /* FPU registers */ |
31 | unsigned long sc_fpregs[16]; | 29 | unsigned long sc_fpregs[16]; |
32 | unsigned long sc_xfpregs[16]; | 30 | unsigned long sc_xfpregs[16]; |
@@ -34,7 +32,6 @@ struct sigcontext { | |||
34 | unsigned int sc_fpul; | 32 | unsigned int sc_fpul; |
35 | unsigned int sc_ownedfp; | 33 | unsigned int sc_ownedfp; |
36 | #endif | 34 | #endif |
37 | #endif | ||
38 | }; | 35 | }; |
39 | 36 | ||
40 | #endif /* __ASM_SH_SIGCONTEXT_H */ | 37 | #endif /* __ASM_SH_SIGCONTEXT_H */ |
diff --git a/arch/sh/include/uapi/asm/unistd_32.h b/arch/sh/include/uapi/asm/unistd_32.h index d13a1d623736..c801bde9e6f5 100644 --- a/arch/sh/include/uapi/asm/unistd_32.h +++ b/arch/sh/include/uapi/asm/unistd_32.h | |||
@@ -380,7 +380,21 @@ | |||
380 | #define __NR_process_vm_writev 366 | 380 | #define __NR_process_vm_writev 366 |
381 | #define __NR_kcmp 367 | 381 | #define __NR_kcmp 367 |
382 | #define __NR_finit_module 368 | 382 | #define __NR_finit_module 368 |
383 | #define __NR_sched_getattr 369 | ||
384 | #define __NR_sched_setattr 370 | ||
385 | #define __NR_renameat2 371 | ||
386 | #define __NR_seccomp 372 | ||
387 | #define __NR_getrandom 373 | ||
388 | #define __NR_memfd_create 374 | ||
389 | #define __NR_bpf 375 | ||
390 | #define __NR_execveat 376 | ||
391 | #define __NR_userfaultfd 377 | ||
392 | #define __NR_membarrier 378 | ||
393 | #define __NR_mlock2 379 | ||
394 | #define __NR_copy_file_range 380 | ||
395 | #define __NR_preadv2 381 | ||
396 | #define __NR_pwritev2 382 | ||
383 | 397 | ||
384 | #define NR_syscalls 369 | 398 | #define NR_syscalls 383 |
385 | 399 | ||
386 | #endif /* __ASM_SH_UNISTD_32_H */ | 400 | #endif /* __ASM_SH_UNISTD_32_H */ |
diff --git a/arch/sh/include/uapi/asm/unistd_64.h b/arch/sh/include/uapi/asm/unistd_64.h index 47ebd5b5ed55..ce0cb3598b62 100644 --- a/arch/sh/include/uapi/asm/unistd_64.h +++ b/arch/sh/include/uapi/asm/unistd_64.h | |||
@@ -400,7 +400,21 @@ | |||
400 | #define __NR_process_vm_writev 377 | 400 | #define __NR_process_vm_writev 377 |
401 | #define __NR_kcmp 378 | 401 | #define __NR_kcmp 378 |
402 | #define __NR_finit_module 379 | 402 | #define __NR_finit_module 379 |
403 | #define __NR_sched_getattr 380 | ||
404 | #define __NR_sched_setattr 381 | ||
405 | #define __NR_renameat2 382 | ||
406 | #define __NR_seccomp 383 | ||
407 | #define __NR_getrandom 384 | ||
408 | #define __NR_memfd_create 385 | ||
409 | #define __NR_bpf 386 | ||
410 | #define __NR_execveat 387 | ||
411 | #define __NR_userfaultfd 388 | ||
412 | #define __NR_membarrier 389 | ||
413 | #define __NR_mlock2 390 | ||
414 | #define __NR_copy_file_range 391 | ||
415 | #define __NR_preadv2 392 | ||
416 | #define __NR_pwritev2 393 | ||
403 | 417 | ||
404 | #define NR_syscalls 380 | 418 | #define NR_syscalls 394 |
405 | 419 | ||
406 | #endif /* __ASM_SH_UNISTD_64_H */ | 420 | #endif /* __ASM_SH_UNISTD_64_H */ |
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 4187cf4fe185..fca9b1e78a63 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c | |||
@@ -24,11 +24,13 @@ int __init clk_init(void) | |||
24 | { | 24 | { |
25 | int ret; | 25 | int ret; |
26 | 26 | ||
27 | #ifndef CONFIG_COMMON_CLK | ||
27 | ret = arch_clk_init(); | 28 | ret = arch_clk_init(); |
28 | if (unlikely(ret)) { | 29 | if (unlikely(ret)) { |
29 | pr_err("%s: CPU clock registration failed.\n", __func__); | 30 | pr_err("%s: CPU clock registration failed.\n", __func__); |
30 | return ret; | 31 | return ret; |
31 | } | 32 | } |
33 | #endif | ||
32 | 34 | ||
33 | if (sh_mv.mv_clk_init) { | 35 | if (sh_mv.mv_clk_init) { |
34 | ret = sh_mv.mv_clk_init(); | 36 | ret = sh_mv.mv_clk_init(); |
@@ -39,11 +41,13 @@ int __init clk_init(void) | |||
39 | } | 41 | } |
40 | } | 42 | } |
41 | 43 | ||
44 | #ifndef CONFIG_COMMON_CLK | ||
42 | /* Kick the child clocks.. */ | 45 | /* Kick the child clocks.. */ |
43 | recalculate_root_clocks(); | 46 | recalculate_root_clocks(); |
44 | 47 | ||
45 | /* Enable the necessary init clocks */ | 48 | /* Enable the necessary init clocks */ |
46 | clk_enable_init_clocks(); | 49 | clk_enable_init_clocks(); |
50 | #endif | ||
47 | 51 | ||
48 | return ret; | 52 | return ret; |
49 | } | 53 | } |
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index 0d7360d549c1..c8b3be1b54e6 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c | |||
@@ -106,7 +106,7 @@ void __attribute__ ((weak)) l2_cache_init(void) | |||
106 | /* | 106 | /* |
107 | * Generic first-level cache init | 107 | * Generic first-level cache init |
108 | */ | 108 | */ |
109 | #ifdef CONFIG_SUPERH32 | 109 | #if defined(CONFIG_SUPERH32) && !defined(CONFIG_CPU_J2) |
110 | static void cache_init(void) | 110 | static void cache_init(void) |
111 | { | 111 | { |
112 | unsigned long ccr, flags; | 112 | unsigned long ccr, flags; |
@@ -323,9 +323,13 @@ asmlinkage void cpu_init(void) | |||
323 | cache_init(); | 323 | cache_init(); |
324 | 324 | ||
325 | if (raw_smp_processor_id() == 0) { | 325 | if (raw_smp_processor_id() == 0) { |
326 | #ifdef CONFIG_MMU | ||
326 | shm_align_mask = max_t(unsigned long, | 327 | shm_align_mask = max_t(unsigned long, |
327 | current_cpu_data.dcache.way_size - 1, | 328 | current_cpu_data.dcache.way_size - 1, |
328 | PAGE_SIZE - 1); | 329 | PAGE_SIZE - 1); |
330 | #else | ||
331 | shm_align_mask = PAGE_SIZE - 1; | ||
332 | #endif | ||
329 | 333 | ||
330 | /* Boot CPU sets the cache shape */ | 334 | /* Boot CPU sets the cache shape */ |
331 | detect_cache_shape(); | 335 | detect_cache_shape(); |
diff --git a/arch/sh/kernel/cpu/proc.c b/arch/sh/kernel/cpu/proc.c index 9e6624c9108b..4df4b284f591 100644 --- a/arch/sh/kernel/cpu/proc.c +++ b/arch/sh/kernel/cpu/proc.c | |||
@@ -27,6 +27,7 @@ static const char *cpu_name[] = { | |||
27 | [CPU_MXG] = "MX-G", [CPU_SH7723] = "SH7723", | 27 | [CPU_MXG] = "MX-G", [CPU_SH7723] = "SH7723", |
28 | [CPU_SH7366] = "SH7366", [CPU_SH7724] = "SH7724", | 28 | [CPU_SH7366] = "SH7366", [CPU_SH7724] = "SH7724", |
29 | [CPU_SH7372] = "SH7372", [CPU_SH7734] = "SH7734", | 29 | [CPU_SH7372] = "SH7372", [CPU_SH7734] = "SH7734", |
30 | [CPU_J2] = "J2", | ||
30 | [CPU_SH_NONE] = "Unknown" | 31 | [CPU_SH_NONE] = "Unknown" |
31 | }; | 32 | }; |
32 | 33 | ||
diff --git a/arch/sh/kernel/cpu/sh2/Makefile b/arch/sh/kernel/cpu/sh2/Makefile index f0f059acfcfb..904c4283d923 100644 --- a/arch/sh/kernel/cpu/sh2/Makefile +++ b/arch/sh/kernel/cpu/sh2/Makefile | |||
@@ -5,3 +5,7 @@ | |||
5 | obj-y := ex.o probe.o entry.o | 5 | obj-y := ex.o probe.o entry.o |
6 | 6 | ||
7 | obj-$(CONFIG_CPU_SUBTYPE_SH7619) += setup-sh7619.o clock-sh7619.o | 7 | obj-$(CONFIG_CPU_SUBTYPE_SH7619) += setup-sh7619.o clock-sh7619.o |
8 | |||
9 | # SMP setup | ||
10 | smp-$(CONFIG_CPU_J2) := smp-j2.o | ||
11 | obj-$(CONFIG_SMP) += $(smp-y) | ||
diff --git a/arch/sh/kernel/cpu/sh2/entry.S b/arch/sh/kernel/cpu/sh2/entry.S index a1505956ef28..1ee0a6e774c6 100644 --- a/arch/sh/kernel/cpu/sh2/entry.S +++ b/arch/sh/kernel/cpu/sh2/entry.S | |||
@@ -47,6 +47,13 @@ ENTRY(exception_handler) | |||
47 | mov.l r3,@-sp | 47 | mov.l r3,@-sp |
48 | cli | 48 | cli |
49 | mov.l $cpu_mode,r2 | 49 | mov.l $cpu_mode,r2 |
50 | #ifdef CONFIG_SMP | ||
51 | mov.l $cpuid,r3 | ||
52 | mov.l @r3,r3 | ||
53 | mov.l @r3,r3 | ||
54 | shll2 r3 | ||
55 | add r3,r2 | ||
56 | #endif | ||
50 | mov.l @r2,r0 | 57 | mov.l @r2,r0 |
51 | mov.l @(5*4,r15),r3 ! previous SR | 58 | mov.l @(5*4,r15),r3 ! previous SR |
52 | or r0,r3 ! set MD | 59 | or r0,r3 ! set MD |
@@ -57,6 +64,13 @@ ENTRY(exception_handler) | |||
57 | mov.l __md_bit,r0 | 64 | mov.l __md_bit,r0 |
58 | mov.l r0,@r2 ! enter kernel mode | 65 | mov.l r0,@r2 ! enter kernel mode |
59 | mov.l $current_thread_info,r2 | 66 | mov.l $current_thread_info,r2 |
67 | #ifdef CONFIG_SMP | ||
68 | mov.l $cpuid,r0 | ||
69 | mov.l @r0,r0 | ||
70 | mov.l @r0,r0 | ||
71 | shll2 r0 | ||
72 | add r0,r2 | ||
73 | #endif | ||
60 | mov.l @r2,r2 | 74 | mov.l @r2,r2 |
61 | mov #(THREAD_SIZE >> 8),r0 | 75 | mov #(THREAD_SIZE >> 8),r0 |
62 | shll8 r0 | 76 | shll8 r0 |
@@ -147,6 +161,11 @@ ENTRY(exception_handler) | |||
147 | mov #31,r8 | 161 | mov #31,r8 |
148 | cmp/hs r8,r9 | 162 | cmp/hs r8,r9 |
149 | bt trap_entry ! 64 > vec >= 31 is trap | 163 | bt trap_entry ! 64 > vec >= 31 is trap |
164 | #ifdef CONFIG_CPU_J2 | ||
165 | mov #16,r8 | ||
166 | cmp/hs r8,r9 | ||
167 | bt interrupt_entry ! 31 > vec >= 16 is interrupt | ||
168 | #endif | ||
150 | 169 | ||
151 | mov.l 4f,r8 | 170 | mov.l 4f,r8 |
152 | mov r9,r4 | 171 | mov r9,r4 |
@@ -260,6 +279,13 @@ restore_all: | |||
260 | lds.l @r0+,macl | 279 | lds.l @r0+,macl |
261 | mov r15,r0 | 280 | mov r15,r0 |
262 | mov.l $cpu_mode,r2 | 281 | mov.l $cpu_mode,r2 |
282 | #ifdef CONFIG_SMP | ||
283 | mov.l $cpuid,r3 | ||
284 | mov.l @r3,r3 | ||
285 | mov.l @r3,r3 | ||
286 | shll2 r3 | ||
287 | add r3,r2 | ||
288 | #endif | ||
263 | mov #OFF_SR,r3 | 289 | mov #OFF_SR,r3 |
264 | mov.l @(r0,r3),r1 | 290 | mov.l @(r0,r3),r1 |
265 | mov.l __md_bit,r3 | 291 | mov.l __md_bit,r3 |
@@ -276,6 +302,13 @@ restore_all: | |||
276 | mov.l r1,@r2 ! set pc | 302 | mov.l r1,@r2 ! set pc |
277 | get_current_thread_info r0, r1 | 303 | get_current_thread_info r0, r1 |
278 | mov.l $current_thread_info,r1 | 304 | mov.l $current_thread_info,r1 |
305 | #ifdef CONFIG_SMP | ||
306 | mov.l $cpuid,r3 | ||
307 | mov.l @r3,r3 | ||
308 | mov.l @r3,r3 | ||
309 | shll2 r3 | ||
310 | add r3,r1 | ||
311 | #endif | ||
279 | mov.l r0,@r1 | 312 | mov.l r0,@r1 |
280 | mov.l @r15+,r0 | 313 | mov.l @r15+,r0 |
281 | mov.l @r15+,r1 | 314 | mov.l @r15+,r1 |
@@ -303,19 +336,41 @@ $current_thread_info: | |||
303 | .long __current_thread_info | 336 | .long __current_thread_info |
304 | $cpu_mode: | 337 | $cpu_mode: |
305 | .long __cpu_mode | 338 | .long __cpu_mode |
339 | #ifdef CONFIG_SMP | ||
340 | $cpuid: | ||
341 | .long sh2_cpuid_addr | ||
342 | #endif | ||
306 | 343 | ||
307 | ! common exception handler | 344 | ! common exception handler |
308 | #include "../../entry-common.S" | 345 | #include "../../entry-common.S" |
346 | |||
347 | #ifdef CONFIG_NR_CPUS | ||
348 | #define NR_CPUS CONFIG_NR_CPUS | ||
349 | #else | ||
350 | #define NR_CPUS 1 | ||
351 | #endif | ||
309 | 352 | ||
310 | .data | 353 | .data |
311 | ! cpu operation mode | 354 | ! cpu operation mode |
312 | ! bit30 = MD (compatible SH3/4) | 355 | ! bit30 = MD (compatible SH3/4) |
313 | __cpu_mode: | 356 | __cpu_mode: |
357 | .rept NR_CPUS | ||
314 | .long 0x40000000 | 358 | .long 0x40000000 |
359 | .endr | ||
360 | |||
361 | #ifdef CONFIG_SMP | ||
362 | .global sh2_cpuid_addr | ||
363 | sh2_cpuid_addr: | ||
364 | .long dummy_cpuid | ||
365 | dummy_cpuid: | ||
366 | .long 0 | ||
367 | #endif | ||
315 | 368 | ||
316 | .section .bss | 369 | .section .bss |
317 | __current_thread_info: | 370 | __current_thread_info: |
371 | .rept NR_CPUS | ||
318 | .long 0 | 372 | .long 0 |
373 | .endr | ||
319 | 374 | ||
320 | ENTRY(exception_handling_table) | 375 | ENTRY(exception_handling_table) |
321 | .space 4*32 | 376 | .space 4*32 |
diff --git a/arch/sh/kernel/cpu/sh2/probe.c b/arch/sh/kernel/cpu/sh2/probe.c index 6c687ae812ef..4205f6d42b69 100644 --- a/arch/sh/kernel/cpu/sh2/probe.c +++ b/arch/sh/kernel/cpu/sh2/probe.c | |||
@@ -10,10 +10,27 @@ | |||
10 | * for more details. | 10 | * for more details. |
11 | */ | 11 | */ |
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/of_fdt.h> | ||
14 | #include <linux/smp.h> | ||
15 | #include <linux/io.h> | ||
13 | #include <asm/processor.h> | 16 | #include <asm/processor.h> |
14 | #include <asm/cache.h> | 17 | #include <asm/cache.h> |
15 | 18 | ||
16 | void cpu_probe(void) | 19 | #if defined(CONFIG_CPU_J2) |
20 | extern u32 __iomem *j2_ccr_base; | ||
21 | static int __init scan_cache(unsigned long node, const char *uname, | ||
22 | int depth, void *data) | ||
23 | { | ||
24 | if (!of_flat_dt_is_compatible(node, "jcore,cache")) | ||
25 | return 0; | ||
26 | |||
27 | j2_ccr_base = (u32 __iomem *)of_flat_dt_translate_address(node); | ||
28 | |||
29 | return 1; | ||
30 | } | ||
31 | #endif | ||
32 | |||
33 | void __ref cpu_probe(void) | ||
17 | { | 34 | { |
18 | #if defined(CONFIG_CPU_SUBTYPE_SH7619) | 35 | #if defined(CONFIG_CPU_SUBTYPE_SH7619) |
19 | boot_cpu_data.type = CPU_SH7619; | 36 | boot_cpu_data.type = CPU_SH7619; |
@@ -24,10 +41,30 @@ void cpu_probe(void) | |||
24 | boot_cpu_data.dcache.linesz = L1_CACHE_BYTES; | 41 | boot_cpu_data.dcache.linesz = L1_CACHE_BYTES; |
25 | boot_cpu_data.dcache.flags = 0; | 42 | boot_cpu_data.dcache.flags = 0; |
26 | #endif | 43 | #endif |
44 | |||
45 | #if defined(CONFIG_CPU_J2) | ||
46 | unsigned cpu = hard_smp_processor_id(); | ||
47 | if (cpu == 0) of_scan_flat_dt(scan_cache, NULL); | ||
48 | if (j2_ccr_base) __raw_writel(0x80000303, j2_ccr_base + 4*cpu); | ||
49 | if (cpu != 0) return; | ||
50 | boot_cpu_data.type = CPU_J2; | ||
51 | |||
52 | /* These defaults are appropriate for the original/current | ||
53 | * J2 cache. Once there is a proper framework for getting cache | ||
54 | * info from device tree, we should switch to that. */ | ||
55 | boot_cpu_data.dcache.ways = 1; | ||
56 | boot_cpu_data.dcache.sets = 256; | ||
57 | boot_cpu_data.dcache.entry_shift = 5; | ||
58 | boot_cpu_data.dcache.linesz = 32; | ||
59 | boot_cpu_data.dcache.flags = 0; | ||
60 | |||
61 | boot_cpu_data.flags |= CPU_HAS_CAS_L; | ||
62 | #else | ||
27 | /* | 63 | /* |
28 | * SH-2 doesn't have separate caches | 64 | * SH-2 doesn't have separate caches |
29 | */ | 65 | */ |
30 | boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED; | 66 | boot_cpu_data.dcache.flags |= SH_CACHE_COMBINED; |
67 | #endif | ||
31 | boot_cpu_data.icache = boot_cpu_data.dcache; | 68 | boot_cpu_data.icache = boot_cpu_data.dcache; |
32 | boot_cpu_data.family = CPU_FAMILY_SH2; | 69 | boot_cpu_data.family = CPU_FAMILY_SH2; |
33 | } | 70 | } |
diff --git a/arch/sh/kernel/cpu/sh2/smp-j2.c b/arch/sh/kernel/cpu/sh2/smp-j2.c new file mode 100644 index 000000000000..6ccd7e4dc008 --- /dev/null +++ b/arch/sh/kernel/cpu/sh2/smp-j2.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * SMP support for J2 processor | ||
3 | * | ||
4 | * Copyright (C) 2015-2016 Smart Energy Instruments, Inc. | ||
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/smp.h> | ||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <linux/of_address.h> | ||
15 | #include <linux/of_irq.h> | ||
16 | #include <asm/cmpxchg.h> | ||
17 | |||
18 | DEFINE_PER_CPU(unsigned, j2_ipi_messages); | ||
19 | |||
20 | extern u32 *sh2_cpuid_addr; | ||
21 | static u32 *j2_ipi_trigger; | ||
22 | static int j2_ipi_irq; | ||
23 | |||
24 | static irqreturn_t j2_ipi_interrupt_handler(int irq, void *arg) | ||
25 | { | ||
26 | unsigned cpu = hard_smp_processor_id(); | ||
27 | volatile unsigned *pmsg = &per_cpu(j2_ipi_messages, cpu); | ||
28 | unsigned messages, i; | ||
29 | |||
30 | do messages = *pmsg; | ||
31 | while (cmpxchg(pmsg, messages, 0) != messages); | ||
32 | |||
33 | if (!messages) return IRQ_NONE; | ||
34 | |||
35 | for (i=0; i<SMP_MSG_NR; i++) | ||
36 | if (messages & (1U<<i)) | ||
37 | smp_message_recv(i); | ||
38 | |||
39 | return IRQ_HANDLED; | ||
40 | } | ||
41 | |||
42 | static void j2_smp_setup(void) | ||
43 | { | ||
44 | } | ||
45 | |||
46 | static void j2_prepare_cpus(unsigned int max_cpus) | ||
47 | { | ||
48 | struct device_node *np; | ||
49 | unsigned i, max = 1; | ||
50 | |||
51 | np = of_find_compatible_node(NULL, NULL, "jcore,ipi-controller"); | ||
52 | if (!np) | ||
53 | goto out; | ||
54 | |||
55 | j2_ipi_irq = irq_of_parse_and_map(np, 0); | ||
56 | j2_ipi_trigger = of_iomap(np, 0); | ||
57 | if (!j2_ipi_irq || !j2_ipi_trigger) | ||
58 | goto out; | ||
59 | |||
60 | np = of_find_compatible_node(NULL, NULL, "jcore,cpuid-mmio"); | ||
61 | if (!np) | ||
62 | goto out; | ||
63 | |||
64 | sh2_cpuid_addr = of_iomap(np, 0); | ||
65 | if (!sh2_cpuid_addr) | ||
66 | goto out; | ||
67 | |||
68 | if (request_irq(j2_ipi_irq, j2_ipi_interrupt_handler, IRQF_PERCPU, | ||
69 | "ipi", (void *)j2_ipi_interrupt_handler) != 0) | ||
70 | goto out; | ||
71 | |||
72 | max = max_cpus; | ||
73 | out: | ||
74 | /* Disable any cpus past max_cpus, or all secondaries if we didn't | ||
75 | * get the necessary resources to support SMP. */ | ||
76 | for (i=max; i<NR_CPUS; i++) { | ||
77 | set_cpu_possible(i, false); | ||
78 | set_cpu_present(i, false); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static void j2_start_cpu(unsigned int cpu, unsigned long entry_point) | ||
83 | { | ||
84 | struct device_node *np; | ||
85 | u32 regs[2]; | ||
86 | void __iomem *release, *initpc; | ||
87 | |||
88 | if (!cpu) return; | ||
89 | |||
90 | np = of_get_cpu_node(cpu, NULL); | ||
91 | if (!np) return; | ||
92 | |||
93 | if (of_property_read_u32_array(np, "cpu-release-addr", regs, 2)) return; | ||
94 | release = ioremap_nocache(regs[0], sizeof(u32)); | ||
95 | initpc = ioremap_nocache(regs[1], sizeof(u32)); | ||
96 | |||
97 | __raw_writel(entry_point, initpc); | ||
98 | __raw_writel(1, release); | ||
99 | |||
100 | iounmap(initpc); | ||
101 | iounmap(release); | ||
102 | |||
103 | pr_info("J2 SMP: requested start of cpu %u\n", cpu); | ||
104 | } | ||
105 | |||
106 | static unsigned int j2_smp_processor_id(void) | ||
107 | { | ||
108 | return __raw_readl(sh2_cpuid_addr); | ||
109 | } | ||
110 | |||
111 | static void j2_send_ipi(unsigned int cpu, unsigned int message) | ||
112 | { | ||
113 | volatile unsigned *pmsg; | ||
114 | unsigned old; | ||
115 | unsigned long val; | ||
116 | |||
117 | /* There is only one IPI interrupt shared by all messages, so | ||
118 | * we keep a separate interrupt flag per message type in sw. */ | ||
119 | pmsg = &per_cpu(j2_ipi_messages, cpu); | ||
120 | do old = *pmsg; | ||
121 | while (cmpxchg(pmsg, old, old|(1U<<message)) != old); | ||
122 | |||
123 | /* Generate the actual interrupt by writing to CCRn bit 28. */ | ||
124 | val = __raw_readl(j2_ipi_trigger + cpu); | ||
125 | __raw_writel(val | (1U<<28), j2_ipi_trigger + cpu); | ||
126 | } | ||
127 | |||
128 | static struct plat_smp_ops j2_smp_ops = { | ||
129 | .smp_setup = j2_smp_setup, | ||
130 | .prepare_cpus = j2_prepare_cpus, | ||
131 | .start_cpu = j2_start_cpu, | ||
132 | .smp_processor_id = j2_smp_processor_id, | ||
133 | .send_ipi = j2_send_ipi, | ||
134 | .cpu_die = native_cpu_die, | ||
135 | .cpu_disable = native_cpu_disable, | ||
136 | .play_dead = native_play_dead, | ||
137 | }; | ||
138 | |||
139 | CPU_METHOD_OF_DECLARE(j2_cpu_method, "jcore,spin-table", &j2_smp_ops); | ||
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c index 9d209a07235e..e1d751ae2498 100644 --- a/arch/sh/kernel/dwarf.c +++ b/arch/sh/kernel/dwarf.c | |||
@@ -1009,10 +1009,8 @@ static void __init dwarf_unwinder_cleanup(void) | |||
1009 | rbtree_postorder_for_each_entry_safe(cie, next_cie, &cie_root, node) | 1009 | rbtree_postorder_for_each_entry_safe(cie, next_cie, &cie_root, node) |
1010 | kfree(cie); | 1010 | kfree(cie); |
1011 | 1011 | ||
1012 | if (dwarf_reg_pool) | 1012 | mempool_destroy(dwarf_reg_pool); |
1013 | mempool_destroy(dwarf_reg_pool); | 1013 | mempool_destroy(dwarf_frame_pool); |
1014 | if (dwarf_frame_pool) | ||
1015 | mempool_destroy(dwarf_frame_pool); | ||
1016 | kmem_cache_destroy(dwarf_reg_cachep); | 1014 | kmem_cache_destroy(dwarf_reg_cachep); |
1017 | kmem_cache_destroy(dwarf_frame_cachep); | 1015 | kmem_cache_destroy(dwarf_frame_cachep); |
1018 | } | 1016 | } |
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S index 974bc152cc84..4e352c3f79e6 100644 --- a/arch/sh/kernel/head_32.S +++ b/arch/sh/kernel/head_32.S | |||
@@ -67,7 +67,7 @@ ENTRY(_stext) | |||
67 | ldc r0, r6_bank | 67 | ldc r0, r6_bank |
68 | #endif | 68 | #endif |
69 | 69 | ||
70 | #ifdef CONFIG_OF | 70 | #ifdef CONFIG_OF_FLATTREE |
71 | mov r4, r12 ! Store device tree blob pointer in r12 | 71 | mov r4, r12 ! Store device tree blob pointer in r12 |
72 | #endif | 72 | #endif |
73 | 73 | ||
@@ -318,7 +318,7 @@ ENTRY(_stext) | |||
318 | 10: | 318 | 10: |
319 | #endif | 319 | #endif |
320 | 320 | ||
321 | #ifdef CONFIG_OF | 321 | #ifdef CONFIG_OF_FLATTREE |
322 | mov.l 8f, r0 ! Make flat device tree available early. | 322 | mov.l 8f, r0 ! Make flat device tree available early. |
323 | jsr @r0 | 323 | jsr @r0 |
324 | mov r12, r4 | 324 | mov r12, r4 |
@@ -349,7 +349,7 @@ ENTRY(stack_start) | |||
349 | 5: .long start_kernel | 349 | 5: .long start_kernel |
350 | 6: .long cpu_init | 350 | 6: .long cpu_init |
351 | 7: .long init_thread_union | 351 | 7: .long init_thread_union |
352 | #if defined(CONFIG_OF) | 352 | #if defined(CONFIG_OF_FLATTREE) |
353 | 8: .long sh_fdt_init | 353 | 8: .long sh_fdt_init |
354 | #endif | 354 | #endif |
355 | 355 | ||
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 5d34605b58b5..e7b49d81053e 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c | |||
@@ -242,7 +242,7 @@ void __init __weak plat_early_device_setup(void) | |||
242 | { | 242 | { |
243 | } | 243 | } |
244 | 244 | ||
245 | #ifdef CONFIG_OF | 245 | #ifdef CONFIG_OF_FLATTREE |
246 | void __ref sh_fdt_init(phys_addr_t dt_phys) | 246 | void __ref sh_fdt_init(phys_addr_t dt_phys) |
247 | { | 247 | { |
248 | static int done = 0; | 248 | static int done = 0; |
@@ -251,7 +251,11 @@ void __ref sh_fdt_init(phys_addr_t dt_phys) | |||
251 | /* Avoid calling an __init function on secondary cpus. */ | 251 | /* Avoid calling an __init function on secondary cpus. */ |
252 | if (done) return; | 252 | if (done) return; |
253 | 253 | ||
254 | #ifdef CONFIG_USE_BUILTIN_DTB | ||
255 | dt_virt = __dtb_start; | ||
256 | #else | ||
254 | dt_virt = phys_to_virt(dt_phys); | 257 | dt_virt = phys_to_virt(dt_phys); |
258 | #endif | ||
255 | 259 | ||
256 | if (!dt_virt || !early_init_dt_scan(dt_virt)) { | 260 | if (!dt_virt || !early_init_dt_scan(dt_virt)) { |
257 | pr_crit("Error: invalid device tree blob" | 261 | pr_crit("Error: invalid device tree blob" |
diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index 734234be2f01..254bc22ee57d 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S | |||
@@ -386,3 +386,17 @@ ENTRY(sys_call_table) | |||
386 | .long sys_process_vm_writev | 386 | .long sys_process_vm_writev |
387 | .long sys_kcmp | 387 | .long sys_kcmp |
388 | .long sys_finit_module | 388 | .long sys_finit_module |
389 | .long sys_sched_getattr | ||
390 | .long sys_sched_setattr /* 370 */ | ||
391 | .long sys_renameat2 | ||
392 | .long sys_seccomp | ||
393 | .long sys_getrandom | ||
394 | .long sys_memfd_create | ||
395 | .long sys_bpf /* 375 */ | ||
396 | .long sys_execveat | ||
397 | .long sys_userfaultfd | ||
398 | .long sys_membarrier | ||
399 | .long sys_mlock2 | ||
400 | .long sys_copy_file_range /* 380 */ | ||
401 | .long sys_preadv2 | ||
402 | .long sys_pwritev2 | ||
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index 579fcb9a896b..d6a27f7a4c54 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S | |||
@@ -406,3 +406,17 @@ sys_call_table: | |||
406 | .long sys_process_vm_writev | 406 | .long sys_process_vm_writev |
407 | .long sys_kcmp | 407 | .long sys_kcmp |
408 | .long sys_finit_module | 408 | .long sys_finit_module |
409 | .long sys_sched_getattr /* 380 */ | ||
410 | .long sys_sched_setattr | ||
411 | .long sys_renameat2 | ||
412 | .long sys_seccomp | ||
413 | .long sys_getrandom | ||
414 | .long sys_memfd_create /* 385 */ | ||
415 | .long sys_bpf | ||
416 | .long sys_execveat | ||
417 | .long sys_userfaultfd | ||
418 | .long sys_membarrier | ||
419 | .long sys_mlock2 /* 390 */ | ||
420 | .long sys_copy_file_range | ||
421 | .long sys_preadv2 | ||
422 | .long sys_pwritev2 | ||
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c index a4a7862b489a..fcd5e41977d1 100644 --- a/arch/sh/kernel/time.c +++ b/arch/sh/kernel/time.c | |||
@@ -11,7 +11,6 @@ | |||
11 | * for more details. | 11 | * for more details. |
12 | */ | 12 | */ |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | 14 | #include <linux/init.h> |
16 | #include <linux/profile.h> | 15 | #include <linux/profile.h> |
17 | #include <linux/timex.h> | 16 | #include <linux/timex.h> |
@@ -90,7 +89,7 @@ static int __init rtc_generic_init(void) | |||
90 | 89 | ||
91 | return PTR_ERR_OR_ZERO(pdev); | 90 | return PTR_ERR_OR_ZERO(pdev); |
92 | } | 91 | } |
93 | module_init(rtc_generic_init); | 92 | device_initcall(rtc_generic_init); |
94 | 93 | ||
95 | void (*board_time_init)(void); | 94 | void (*board_time_init)(void); |
96 | 95 | ||
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile index cee6b9999d86..92c3bd96aee5 100644 --- a/arch/sh/mm/Makefile +++ b/arch/sh/mm/Makefile | |||
@@ -4,7 +4,8 @@ | |||
4 | 4 | ||
5 | obj-y := alignment.o cache.o init.o consistent.o mmap.o | 5 | obj-y := alignment.o cache.o init.o consistent.o mmap.o |
6 | 6 | ||
7 | cacheops-$(CONFIG_CPU_SH2) := cache-sh2.o | 7 | cacheops-$(CONFIG_CPU_J2) := cache-j2.o |
8 | cacheops-$(CONFIG_CPU_SUBTYPE_SH7619) := cache-sh2.o | ||
8 | cacheops-$(CONFIG_CPU_SH2A) := cache-sh2a.o | 9 | cacheops-$(CONFIG_CPU_SH2A) := cache-sh2a.o |
9 | cacheops-$(CONFIG_CPU_SH3) := cache-sh3.o | 10 | cacheops-$(CONFIG_CPU_SH3) := cache-sh3.o |
10 | cacheops-$(CONFIG_CPU_SH4) := cache-sh4.o flush-sh4.o | 11 | cacheops-$(CONFIG_CPU_SH4) := cache-sh4.o flush-sh4.o |
diff --git a/arch/sh/mm/asids-debugfs.c b/arch/sh/mm/asids-debugfs.c index ecfc6b0c1da1..bf95fdaedd0c 100644 --- a/arch/sh/mm/asids-debugfs.c +++ b/arch/sh/mm/asids-debugfs.c | |||
@@ -17,7 +17,6 @@ | |||
17 | * for more details. | 17 | * for more details. |
18 | */ | 18 | */ |
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/module.h> | ||
21 | #include <linux/debugfs.h> | 20 | #include <linux/debugfs.h> |
22 | #include <linux/seq_file.h> | 21 | #include <linux/seq_file.h> |
23 | #include <linux/spinlock.h> | 22 | #include <linux/spinlock.h> |
@@ -70,6 +69,4 @@ static int __init asids_debugfs_init(void) | |||
70 | 69 | ||
71 | return PTR_ERR_OR_ZERO(asids_dentry); | 70 | return PTR_ERR_OR_ZERO(asids_dentry); |
72 | } | 71 | } |
73 | module_init(asids_debugfs_init); | 72 | device_initcall(asids_debugfs_init); |
74 | |||
75 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/arch/sh/mm/cache-j2.c b/arch/sh/mm/cache-j2.c new file mode 100644 index 000000000000..391698bcac5b --- /dev/null +++ b/arch/sh/mm/cache-j2.c | |||
@@ -0,0 +1,65 @@ | |||
1 | /* | ||
2 | * arch/sh/mm/cache-j2.c | ||
3 | * | ||
4 | * Copyright (C) 2015-2016 Smart Energy Instruments, Inc. | ||
5 | * | ||
6 | * Released under the terms of the GNU GPL v2.0. | ||
7 | */ | ||
8 | |||
9 | #include <linux/init.h> | ||
10 | #include <linux/mm.h> | ||
11 | #include <linux/cpumask.h> | ||
12 | |||
13 | #include <asm/cache.h> | ||
14 | #include <asm/addrspace.h> | ||
15 | #include <asm/processor.h> | ||
16 | #include <asm/cacheflush.h> | ||
17 | #include <asm/io.h> | ||
18 | |||
19 | #define ICACHE_ENABLE 0x1 | ||
20 | #define DCACHE_ENABLE 0x2 | ||
21 | #define CACHE_ENABLE (ICACHE_ENABLE | DCACHE_ENABLE) | ||
22 | #define ICACHE_FLUSH 0x100 | ||
23 | #define DCACHE_FLUSH 0x200 | ||
24 | #define CACHE_FLUSH (ICACHE_FLUSH | DCACHE_FLUSH) | ||
25 | |||
26 | u32 __iomem *j2_ccr_base; | ||
27 | |||
28 | static void j2_flush_icache(void *args) | ||
29 | { | ||
30 | unsigned cpu; | ||
31 | for_each_possible_cpu(cpu) | ||
32 | __raw_writel(CACHE_ENABLE | ICACHE_FLUSH, j2_ccr_base + cpu); | ||
33 | } | ||
34 | |||
35 | static void j2_flush_dcache(void *args) | ||
36 | { | ||
37 | unsigned cpu; | ||
38 | for_each_possible_cpu(cpu) | ||
39 | __raw_writel(CACHE_ENABLE | DCACHE_FLUSH, j2_ccr_base + cpu); | ||
40 | } | ||
41 | |||
42 | static void j2_flush_both(void *args) | ||
43 | { | ||
44 | unsigned cpu; | ||
45 | for_each_possible_cpu(cpu) | ||
46 | __raw_writel(CACHE_ENABLE | CACHE_FLUSH, j2_ccr_base + cpu); | ||
47 | } | ||
48 | |||
49 | void __init j2_cache_init(void) | ||
50 | { | ||
51 | if (!j2_ccr_base) | ||
52 | return; | ||
53 | |||
54 | local_flush_cache_all = j2_flush_both; | ||
55 | local_flush_cache_mm = j2_flush_both; | ||
56 | local_flush_cache_dup_mm = j2_flush_both; | ||
57 | local_flush_cache_page = j2_flush_both; | ||
58 | local_flush_cache_range = j2_flush_both; | ||
59 | local_flush_dcache_page = j2_flush_dcache; | ||
60 | local_flush_icache_range = j2_flush_icache; | ||
61 | local_flush_icache_page = j2_flush_icache; | ||
62 | local_flush_cache_sigtramp = j2_flush_icache; | ||
63 | |||
64 | pr_info("Initial J2 CCR is %.8x\n", __raw_readl(j2_ccr_base)); | ||
65 | } | ||
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c index e58cfbf45150..36554a9ea99b 100644 --- a/arch/sh/mm/cache.c +++ b/arch/sh/mm/cache.c | |||
@@ -42,6 +42,8 @@ static inline void cacheop_on_each_cpu(void (*func) (void *info), void *info, | |||
42 | { | 42 | { |
43 | preempt_disable(); | 43 | preempt_disable(); |
44 | 44 | ||
45 | /* Needing IPI for cross-core flush is SHX3-specific. */ | ||
46 | #ifdef CONFIG_CPU_SHX3 | ||
45 | /* | 47 | /* |
46 | * It's possible that this gets called early on when IRQs are | 48 | * It's possible that this gets called early on when IRQs are |
47 | * still disabled due to ioremapping by the boot CPU, so don't | 49 | * still disabled due to ioremapping by the boot CPU, so don't |
@@ -49,6 +51,7 @@ static inline void cacheop_on_each_cpu(void (*func) (void *info), void *info, | |||
49 | */ | 51 | */ |
50 | if (num_online_cpus() > 1) | 52 | if (num_online_cpus() > 1) |
51 | smp_call_function(func, info, wait); | 53 | smp_call_function(func, info, wait); |
54 | #endif | ||
52 | 55 | ||
53 | func(info); | 56 | func(info); |
54 | 57 | ||
@@ -244,7 +247,11 @@ void flush_cache_sigtramp(unsigned long address) | |||
244 | 247 | ||
245 | static void compute_alias(struct cache_info *c) | 248 | static void compute_alias(struct cache_info *c) |
246 | { | 249 | { |
250 | #ifdef CONFIG_MMU | ||
247 | c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1); | 251 | c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1); |
252 | #else | ||
253 | c->alias_mask = 0; | ||
254 | #endif | ||
248 | c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0; | 255 | c->n_aliases = c->alias_mask ? (c->alias_mask >> PAGE_SHIFT) + 1 : 0; |
249 | } | 256 | } |
250 | 257 | ||
@@ -305,7 +312,11 @@ void __init cpu_cache_init(void) | |||
305 | if (unlikely(cache_disabled)) | 312 | if (unlikely(cache_disabled)) |
306 | goto skip; | 313 | goto skip; |
307 | 314 | ||
308 | if (boot_cpu_data.family == CPU_FAMILY_SH2) { | 315 | if (boot_cpu_data.type == CPU_J2) { |
316 | extern void __weak j2_cache_init(void); | ||
317 | |||
318 | j2_cache_init(); | ||
319 | } else if (boot_cpu_data.family == CPU_FAMILY_SH2) { | ||
309 | extern void __weak sh2_cache_init(void); | 320 | extern void __weak sh2_cache_init(void); |
310 | 321 | ||
311 | sh2_cache_init(); | 322 | sh2_cache_init(); |