Skip to content
Snippets Groups Projects
Commit 1630e843 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
  ...
parents 194d6ad3 e61c10e4
No related branches found
No related tags found
No related merge requests found
Showing
with 462 additions and 159 deletions
...@@ -38,6 +38,7 @@ config SUPERH ...@@ -38,6 +38,7 @@ config SUPERH
select GENERIC_IDLE_POLL_SETUP select GENERIC_IDLE_POLL_SETUP
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST
select GENERIC_SCHED_CLOCK
select GENERIC_STRNCPY_FROM_USER select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER select GENERIC_STRNLEN_USER
select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER
...@@ -45,6 +46,7 @@ config SUPERH ...@@ -45,6 +46,7 @@ config SUPERH
select OLD_SIGSUSPEND select OLD_SIGSUSPEND
select OLD_SIGACTION select OLD_SIGACTION
select HAVE_ARCH_AUDITSYSCALL select HAVE_ARCH_AUDITSYSCALL
select HAVE_FUTEX_CMPXCHG if FUTEX
select HAVE_NMI select HAVE_NMI
help help
The SuperH is a RISC processor targeted for use in embedded systems The SuperH is a RISC processor targeted for use in embedded systems
...@@ -184,6 +186,12 @@ config CPU_SH2A ...@@ -184,6 +186,12 @@ config CPU_SH2A
select CPU_SH2 select CPU_SH2
select UNCACHED_MAPPING select UNCACHED_MAPPING
config CPU_J2
bool
select CPU_SH2
select OF
select OF_EARLY_FLATTREE
config CPU_SH3 config CPU_SH3
bool bool
select CPU_HAS_INTEVT select CPU_HAS_INTEVT
...@@ -250,6 +258,12 @@ config CPU_SUBTYPE_SH7619 ...@@ -250,6 +258,12 @@ config CPU_SUBTYPE_SH7619
select CPU_SH2 select CPU_SH2
select SYS_SUPPORTS_SH_CMT select SYS_SUPPORTS_SH_CMT
config CPU_SUBTYPE_J2
bool "Support J2 processor"
select CPU_J2
select SYS_SUPPORTS_SMP
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
# SH-2A Processor Support # SH-2A Processor Support
config CPU_SUBTYPE_SH7201 config CPU_SUBTYPE_SH7201
...@@ -739,6 +753,26 @@ endmenu ...@@ -739,6 +753,26 @@ endmenu
menu "Boot options" menu "Boot options"
config USE_BUILTIN_DTB
bool "Use builtin DTB"
default n
depends on SH_DEVICE_TREE
help
Link a device tree blob for particular hardware into the kernel,
suppressing use of the DTB pointer provided by the bootloader.
This option should only be used with legacy bootloaders that are
not capable of providing a DTB to the kernel, or for experimental
hardware without stable device tree bindings.
config BUILTIN_DTB_SOURCE
string "Source file for builtin DTB"
default ""
depends on USE_BUILTIN_DTB
help
Base name (without suffix, relative to arch/sh/boot/dts) for the
a DTS file that will be used to produce the DTB linked into the
kernel.
config ZERO_PAGE_OFFSET config ZERO_PAGE_OFFSET
hex hex
default "0x00010000" if PAGE_SIZE_64KB || SH_RTS7751R2D || \ default "0x00010000" if PAGE_SIZE_64KB || SH_RTS7751R2D || \
......
...@@ -31,6 +31,7 @@ isa-y := $(isa-y)-up ...@@ -31,6 +31,7 @@ isa-y := $(isa-y)-up
endif endif
cflags-$(CONFIG_CPU_SH2) := $(call cc-option,-m2,) cflags-$(CONFIG_CPU_SH2) := $(call cc-option,-m2,)
cflags-$(CONFIG_CPU_J2) := $(call cc-option,-mj2,)
cflags-$(CONFIG_CPU_SH2A) += $(call cc-option,-m2a,) \ cflags-$(CONFIG_CPU_SH2A) += $(call cc-option,-m2a,) \
$(call cc-option,-m2a-nofpu,) \ $(call cc-option,-m2a-nofpu,) \
$(call cc-option,-m4-nofpu,) $(call cc-option,-m4-nofpu,)
...@@ -130,6 +131,8 @@ head-y := arch/sh/kernel/head_$(BITS).o ...@@ -130,6 +131,8 @@ head-y := arch/sh/kernel/head_$(BITS).o
core-y += arch/sh/kernel/ arch/sh/mm/ arch/sh/boards/ core-y += arch/sh/kernel/ arch/sh/mm/ arch/sh/boards/
core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/ core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/
core-$(CONFIG_USE_BUILTIN_DTB) += arch/sh/boot/dts/
# Mach groups # Mach groups
machdir-$(CONFIG_SOLUTION_ENGINE) += mach-se machdir-$(CONFIG_SOLUTION_ENGINE) += mach-se
machdir-$(CONFIG_SH_HP6XX) += mach-hp6xx machdir-$(CONFIG_SH_HP6XX) += mach-hp6xx
......
...@@ -11,6 +11,7 @@ config SH_DEVICE_TREE ...@@ -11,6 +11,7 @@ config SH_DEVICE_TREE
select OF select OF
select OF_EARLY_FLATTREE select OF_EARLY_FLATTREE
select CLKSRC_OF select CLKSRC_OF
select COMMON_CLK
select GENERIC_CALIBRATE_DELAY select GENERIC_CALIBRATE_DELAY
help help
Select Board Described by Device Tree to build a kernel that Select Board Described by Device Tree to build a kernel that
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/module.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <asm/machvec.h> #include <asm/machvec.h>
#include <mach/secureedge5410.h> #include <mach/secureedge5410.h>
...@@ -49,7 +48,7 @@ static int __init eraseconfig_init(void) ...@@ -49,7 +48,7 @@ static int __init eraseconfig_init(void)
irq); irq);
return 0; return 0;
} }
module_init(eraseconfig_init); device_initcall(eraseconfig_init);
/* /*
* Initialize IRQ setting * Initialize IRQ setting
......
...@@ -124,13 +124,22 @@ static void __init sh_of_time_init(void) ...@@ -124,13 +124,22 @@ static void __init sh_of_time_init(void)
static void __init sh_of_setup(char **cmdline_p) static void __init sh_of_setup(char **cmdline_p)
{ {
struct device_node *root;
#ifdef CONFIG_USE_BUILTIN_DTB
unflatten_and_copy_device_tree();
#else
unflatten_device_tree(); unflatten_device_tree();
#endif
board_time_init = sh_of_time_init; board_time_init = sh_of_time_init;
sh_mv.mv_name = of_flat_dt_get_machine_name(); sh_mv.mv_name = "Unknown SH model";
if (!sh_mv.mv_name) root = of_find_node_by_path("/");
sh_mv.mv_name = "Unknown SH model"; if (root) {
of_property_read_string(root, "model", &sh_mv.mv_name);
of_node_put(root);
}
sh_of_smp_probe(); sh_of_smp_probe();
} }
......
obj-$(CONFIG_USE_BUILTIN_DTB) += $(patsubst "%",%,$(CONFIG_BUILTIN_DTB_SOURCE)).dtb.o
clean-files := *.dtb.S
/dts-v1/;
/ {
compatible = "jcore,j2-soc";
model = "J2 FPGA SoC on Mimas v2 board";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&aic>;
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "jcore,j2";
reg = <0>;
clock-frequency = <50000000>;
d-cache-size = <8192>;
i-cache-size = <8192>;
d-cache-block-size = <16>;
i-cache-block-size = <16>;
};
};
memory@10000000 {
device_type = "memory";
reg = <0x10000000 0x4000000>;
};
aliases {
serial0 = &uart0;
spi0 = &spi0;
};
chosen {
stdout-path = "serial0";
};
soc@abcd0000 {
compatible = "simple-bus";
ranges = <0 0xabcd0000 0x100000>;
#address-cells = <1>;
#size-cells = <1>;
aic: interrupt-controller@200 {
compatible = "jcore,aic1";
reg = <0x200 0x10>;
interrupt-controller;
#interrupt-cells = <1>;
};
cache-controller@c0 {
compatible = "jcore,cache";
reg = <0xc0 4>;
};
timer@200 {
compatible = "jcore,pit";
reg = <0x200 0x30>;
interrupts = <0x48>;
};
spi0: spi@40 {
compatible = "jcore,spi2";
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <25000000>;
reg = <0x40 0x8>;
sdcard@0 {
compatible = "mmc-spi-slot";
reg = <0>;
spi-max-frequency = <25000000>;
voltage-ranges = <3200 3400>;
mode = <0>;
};
};
uart0: serial@100 {
clock-frequency = <125000000>;
compatible = "xlnx,xps-uartlite-1.00.a";
current-speed = <19200>;
device_type = "serial";
interrupts = <0x12>;
port-number = <0>;
reg = <0x100 0x10>;
};
};
};
CONFIG_SMP=y
CONFIG_SYSVIPC=y
CONFIG_POSIX_MQUEUE=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_CPU_SUBTYPE_J2=y
CONFIG_MEMORY_START=0x10000000
CONFIG_MEMORY_SIZE=0x04000000
CONFIG_CPU_BIG_ENDIAN=y
CONFIG_SH_DEVICE_TREE=y
CONFIG_HZ_100=y
CONFIG_CMDLINE_OVERWRITE=y
CONFIG_CMDLINE="console=ttyUL0 earlycon"
CONFIG_BINFMT_ELF_FDPIC=y
CONFIG_BINFMT_FLAT=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_NETDEVICES=y
CONFIG_SERIAL_UARTLITE=y
CONFIG_SERIAL_UARTLITE_CONSOLE=y
CONFIG_I2C=y
CONFIG_SPI=y
CONFIG_SPI_JCORE=y
CONFIG_WATCHDOG=y
CONFIG_MMC=y
CONFIG_MMC_SPI=y
CONFIG_CLKSRC_JCORE_PIT=y
CONFIG_JCORE_AIC=y
CONFIG_EXT4_FS=y
CONFIG_VFAT_FS=y
CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
CONFIG_FAT_DEFAULT_UTF8=y
CONFIG_NLS_DEFAULT="utf8"
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_UTF8=y
...@@ -19,7 +19,6 @@ ...@@ -19,7 +19,6 @@
* for more details. * for more details.
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/timer.h> #include <linux/timer.h>
...@@ -139,26 +138,11 @@ static int heartbeat_drv_probe(struct platform_device *pdev) ...@@ -139,26 +138,11 @@ static int heartbeat_drv_probe(struct platform_device *pdev)
return mod_timer(&hd->timer, jiffies + 1); return mod_timer(&hd->timer, jiffies + 1);
} }
static int heartbeat_drv_remove(struct platform_device *pdev)
{
struct heartbeat_data *hd = platform_get_drvdata(pdev);
del_timer_sync(&hd->timer);
iounmap(hd->base);
platform_set_drvdata(pdev, NULL);
if (!pdev->dev.platform_data)
kfree(hd);
return 0;
}
static struct platform_driver heartbeat_driver = { static struct platform_driver heartbeat_driver = {
.probe = heartbeat_drv_probe, .probe = heartbeat_drv_probe,
.remove = heartbeat_drv_remove,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.suppress_bind_attrs = true,
}, },
}; };
...@@ -167,14 +151,4 @@ static int __init heartbeat_init(void) ...@@ -167,14 +151,4 @@ static int __init heartbeat_init(void)
printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION); printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION);
return platform_driver_register(&heartbeat_driver); return platform_driver_register(&heartbeat_driver);
} }
device_initcall(heartbeat_init);
static void __exit heartbeat_exit(void)
{
platform_driver_unregister(&heartbeat_driver);
}
module_init(heartbeat_init);
module_exit(heartbeat_exit);
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR("Paul Mundt");
MODULE_LICENSE("GPL v2");
#ifndef __ASM_SH_ATOMIC_H #ifndef __ASM_SH_ATOMIC_H
#define __ASM_SH_ATOMIC_H #define __ASM_SH_ATOMIC_H
#if defined(CONFIG_CPU_J2)
#include <asm-generic/atomic.h>
#else
/* /*
* Atomic operations that C can't guarantee us. Useful for * Atomic operations that C can't guarantee us. Useful for
* resource counting etc.. * resource counting etc..
...@@ -63,4 +69,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) ...@@ -63,4 +69,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
return c; return c;
} }
#endif /* CONFIG_CPU_J2 */
#endif /* __ASM_SH_ATOMIC_H */ #endif /* __ASM_SH_ATOMIC_H */
...@@ -29,6 +29,11 @@ ...@@ -29,6 +29,11 @@
#define wmb() mb() #define wmb() mb()
#define ctrl_barrier() __icbi(PAGE_OFFSET) #define ctrl_barrier() __icbi(PAGE_OFFSET)
#else #else
#if defined(CONFIG_CPU_J2) && defined(CONFIG_SMP)
#define __smp_mb() do { int tmp = 0; __asm__ __volatile__ ("cas.l %0,%0,@%1" : "+r"(tmp) : "z"(&tmp) : "memory", "t"); } while(0)
#define __smp_rmb() __smp_mb()
#define __smp_wmb() __smp_mb()
#endif
#define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop") #define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
#endif #endif
......
#ifndef __ASM_SH_BITOPS_CAS_H
#define __ASM_SH_BITOPS_CAS_H
static inline unsigned __bo_cas(volatile unsigned *p, unsigned old, unsigned new)
{
__asm__ __volatile__("cas.l %1,%0,@r0"
: "+r"(new)
: "r"(old), "z"(p)
: "t", "memory" );
return new;
}
static inline void set_bit(int nr, volatile void *addr)
{
unsigned mask, old;
volatile unsigned *a = addr;
a += nr >> 5;
mask = 1U << (nr & 0x1f);
do old = *a;
while (__bo_cas(a, old, old|mask) != old);
}
static inline void clear_bit(int nr, volatile void *addr)
{
unsigned mask, old;
volatile unsigned *a = addr;
a += nr >> 5;
mask = 1U << (nr & 0x1f);
do old = *a;
while (__bo_cas(a, old, old&~mask) != old);
}
static inline void change_bit(int nr, volatile void *addr)
{
unsigned mask, old;
volatile unsigned *a = addr;
a += nr >> 5;
mask = 1U << (nr & 0x1f);
do old = *a;
while (__bo_cas(a, old, old^mask) != old);
}
static inline int test_and_set_bit(int nr, volatile void *addr)
{
unsigned mask, old;
volatile unsigned *a = addr;
a += nr >> 5;
mask = 1U << (nr & 0x1f);
do old = *a;
while (__bo_cas(a, old, old|mask) != old);
return !!(old & mask);
}
static inline int test_and_clear_bit(int nr, volatile void *addr)
{
unsigned mask, old;
volatile unsigned *a = addr;
a += nr >> 5;
mask = 1U << (nr & 0x1f);
do old = *a;
while (__bo_cas(a, old, old&~mask) != old);
return !!(old & mask);
}
static inline int test_and_change_bit(int nr, volatile void *addr)
{
unsigned mask, old;
volatile unsigned *a = addr;
a += nr >> 5;
mask = 1U << (nr & 0x1f);
do old = *a;
while (__bo_cas(a, old, old^mask) != old);
return !!(old & mask);
}
#include <asm-generic/bitops/non-atomic.h>
#endif /* __ASM_SH_BITOPS_CAS_H */
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <asm/bitops-op32.h> #include <asm/bitops-op32.h>
#elif defined(CONFIG_CPU_SH4A) #elif defined(CONFIG_CPU_SH4A)
#include <asm/bitops-llsc.h> #include <asm/bitops-llsc.h>
#elif defined(CONFIG_CPU_J2) && defined(CONFIG_SMP)
#include <asm/bitops-cas.h>
#else #else
#include <asm-generic/bitops/atomic.h> #include <asm-generic/bitops/atomic.h>
#include <asm-generic/bitops/non-atomic.h> #include <asm-generic/bitops/non-atomic.h>
......
#ifndef __ASM_SH_CMPXCHG_CAS_H
#define __ASM_SH_CMPXCHG_CAS_H
static inline unsigned long
__cmpxchg_u32(volatile u32 *m, unsigned long old, unsigned long new)
{
__asm__ __volatile__("cas.l %1,%0,@r0"
: "+r"(new)
: "r"(old), "z"(m)
: "t", "memory" );
return new;
}
static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
{
unsigned long old;
do old = *m;
while (__cmpxchg_u32(m, old, val) != old);
return old;
}
#include <asm/cmpxchg-xchg.h>
#endif /* __ASM_SH_CMPXCHG_CAS_H */
...@@ -21,7 +21,7 @@ static inline u32 __xchg_cmpxchg(volatile void *ptr, u32 x, int size) ...@@ -21,7 +21,7 @@ static inline u32 __xchg_cmpxchg(volatile void *ptr, u32 x, int size)
int off = (unsigned long)ptr % sizeof(u32); int off = (unsigned long)ptr % sizeof(u32);
volatile u32 *p = ptr - off; volatile u32 *p = ptr - off;
#ifdef __BIG_ENDIAN #ifdef __BIG_ENDIAN
int bitoff = (sizeof(u32) - 1 - off) * BITS_PER_BYTE; int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
#else #else
int bitoff = off * BITS_PER_BYTE; int bitoff = off * BITS_PER_BYTE;
#endif #endif
......
...@@ -13,6 +13,8 @@ ...@@ -13,6 +13,8 @@
#include <asm/cmpxchg-grb.h> #include <asm/cmpxchg-grb.h>
#elif defined(CONFIG_CPU_SH4A) #elif defined(CONFIG_CPU_SH4A)
#include <asm/cmpxchg-llsc.h> #include <asm/cmpxchg-llsc.h>
#elif defined(CONFIG_CPU_J2) && defined(CONFIG_SMP)
#include <asm/cmpxchg-cas.h>
#else #else
#include <asm/cmpxchg-irq.h> #include <asm/cmpxchg-irq.h>
#endif #endif
......
#ifndef __ASM_SH_FUTEX_CAS_H
#define __ASM_SH_FUTEX_CAS_H
static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
u32 __user *uaddr,
u32 oldval, u32 newval)
{
int err = 0;
__asm__ __volatile__(
"1:\n\t"
"cas.l %2, %1, @r0\n"
"2:\n\t"
#ifdef CONFIG_MMU
".section .fixup,\"ax\"\n"
"3:\n\t"
"mov.l 4f, %0\n\t"
"jmp @%0\n\t"
" mov %3, %0\n\t"
".balign 4\n"
"4: .long 2b\n\t"
".previous\n"
".section __ex_table,\"a\"\n\t"
".long 1b, 3b\n\t"
".previous"
#endif
:"+r" (err), "+r" (newval)
:"r" (oldval), "i" (-EFAULT), "z" (uaddr)
:"t", "memory");
if (err) return err;
*uval = newval;
return 0;
}
#endif /* __ASM_SH_FUTEX_CAS_H */
#ifndef __ASM_SH_FUTEX_IRQ_H #ifndef __ASM_SH_FUTEX_IRQ_H
#define __ASM_SH_FUTEX_IRQ_H #define __ASM_SH_FUTEX_IRQ_H
static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
int ret;
local_irq_save(flags);
ret = get_user(*oldval, uaddr);
if (!ret)
ret = put_user(oparg, uaddr);
local_irq_restore(flags);
return ret;
}
static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
int ret;
local_irq_save(flags);
ret = get_user(*oldval, uaddr);
if (!ret)
ret = put_user(*oldval + oparg, uaddr);
local_irq_restore(flags);
return ret;
}
static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
int ret;
local_irq_save(flags);
ret = get_user(*oldval, uaddr);
if (!ret)
ret = put_user(*oldval | oparg, uaddr);
local_irq_restore(flags);
return ret;
}
static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
int ret;
local_irq_save(flags);
ret = get_user(*oldval, uaddr);
if (!ret)
ret = put_user(*oldval & oparg, uaddr);
local_irq_restore(flags);
return ret;
}
static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr,
int *oldval)
{
unsigned long flags;
int ret;
local_irq_save(flags);
ret = get_user(*oldval, uaddr);
if (!ret)
ret = put_user(*oldval ^ oparg, uaddr);
local_irq_restore(flags);
return ret;
}
static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval, static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
u32 __user *uaddr, u32 __user *uaddr,
u32 oldval, u32 newval) u32 oldval, u32 newval)
......
#ifndef __ASM_SH_FUTEX_LLSC_H
#define __ASM_SH_FUTEX_LLSC_H
static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval,
u32 __user *uaddr,
u32 oldval, u32 newval)
{
int err = 0;
__asm__ __volatile__(
"synco\n"
"1:\n\t"
"movli.l @%2, r0\n\t"
"mov r0, %1\n\t"
"cmp/eq %1, %4\n\t"
"bf 2f\n\t"
"mov %5, r0\n\t"
"movco.l r0, @%2\n\t"
"bf 1b\n"
"2:\n\t"
"synco\n\t"
#ifdef CONFIG_MMU
".section .fixup,\"ax\"\n"
"3:\n\t"
"mov.l 4f, %0\n\t"
"jmp @%0\n\t"
" mov %3, %0\n\t"
".balign 4\n"
"4: .long 2b\n\t"
".previous\n"
".section __ex_table,\"a\"\n\t"
".long 1b, 3b\n\t"
".previous"
#endif
:"+r" (err), "=&r" (*uval)
:"r" (uaddr), "i" (-EFAULT), "r" (oldval), "r" (newval)
:"t", "memory", "r0");
if (err) return err;
return 0;
}
#endif /* __ASM_SH_FUTEX_LLSC_H */
...@@ -7,16 +7,34 @@ ...@@ -7,16 +7,34 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/errno.h> #include <asm/errno.h>
/* XXX: UP variants, fix for SH-4A and SMP.. */ #if !defined(CONFIG_SMP)
#include <asm/futex-irq.h> #include <asm/futex-irq.h>
#elif defined(CONFIG_CPU_J2)
#include <asm/futex-cas.h>
#elif defined(CONFIG_CPU_SH4A)
#include <asm/futex-llsc.h>
#else
#error SMP not supported on this configuration.
#endif
static inline int
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
u32 oldval, u32 newval)
{
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;
return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
}
static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
{ {
int op = (encoded_op >> 28) & 7; int op = (encoded_op >> 28) & 7;
int cmp = (encoded_op >> 24) & 15; int cmp = (encoded_op >> 24) & 15;
int oparg = (encoded_op << 8) >> 20; u32 oparg = (encoded_op << 8) >> 20;
int cmparg = (encoded_op << 20) >> 20; u32 cmparg = (encoded_op << 20) >> 20;
int oldval = 0, ret; u32 oldval, newval, prev;
int ret;
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
oparg = 1 << oparg; oparg = 1 << oparg;
...@@ -26,26 +44,39 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) ...@@ -26,26 +44,39 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
pagefault_disable(); pagefault_disable();
switch (op) { do {
case FUTEX_OP_SET: if (op == FUTEX_OP_SET)
ret = atomic_futex_op_xchg_set(oparg, uaddr, &oldval); ret = oldval = 0;
break; else
case FUTEX_OP_ADD: ret = get_user(oldval, uaddr);
ret = atomic_futex_op_xchg_add(oparg, uaddr, &oldval);
break; if (ret) break;
case FUTEX_OP_OR:
ret = atomic_futex_op_xchg_or(oparg, uaddr, &oldval); switch (op) {
break; case FUTEX_OP_SET:
case FUTEX_OP_ANDN: newval = oparg;
ret = atomic_futex_op_xchg_and(~oparg, uaddr, &oldval); break;
break; case FUTEX_OP_ADD:
case FUTEX_OP_XOR: newval = oldval + oparg;
ret = atomic_futex_op_xchg_xor(oparg, uaddr, &oldval); break;
break; case FUTEX_OP_OR:
default: newval = oldval | oparg;
ret = -ENOSYS; break;
break; case FUTEX_OP_ANDN:
} newval = oldval & ~oparg;
break;
case FUTEX_OP_XOR:
newval = oldval ^ oparg;
break;
default:
ret = -ENOSYS;
break;
}
if (ret) break;
ret = futex_atomic_cmpxchg_inatomic(&prev, uaddr, oldval, newval);
} while (!ret && prev != oldval);
pagefault_enable(); pagefault_enable();
...@@ -53,10 +84,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) ...@@ -53,10 +84,10 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
switch (cmp) { switch (cmp) {
case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; case FUTEX_OP_CMP_LT: ret = ((int)oldval < (int)cmparg); break;
case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; case FUTEX_OP_CMP_GE: ret = ((int)oldval >= (int)cmparg); break;
case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; case FUTEX_OP_CMP_LE: ret = ((int)oldval <= (int)cmparg); break;
case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; case FUTEX_OP_CMP_GT: ret = ((int)oldval > (int)cmparg); break;
default: ret = -ENOSYS; default: ret = -ENOSYS;
} }
} }
...@@ -64,15 +95,5 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) ...@@ -64,15 +95,5 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
return ret; return ret;
} }
static inline int
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
u32 oldval, u32 newval)
{
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
return -EFAULT;
return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval);
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __ASM_SH_FUTEX_H */ #endif /* __ASM_SH_FUTEX_H */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment