aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arc
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2016-10-20 10:39:45 -0400
committerVineet Gupta <vgupta@synopsys.com>2016-10-24 12:24:26 -0400
commit91e040a79df73d371f70792f30380d4e44805250 (patch)
treeb2732eadb60fc5575c465a81cc637a899330c1b5 /arch/arc
parent1dec78585328db00e33fb18dc1a6deed0e2095a5 (diff)
ARC: syscall for userspace cmpxchg assist
Older ARC700 cores (ARC750 specifically) lack instructions to implement atomic r-w-w. This is problematic for userspace libraries such as NPTL which need atomic primitives. So enable them by providing kernel assist. This is costly but really the only sane soluton (othern than tight spinning using the otherwise availiable atomic exchange EX instruciton). Good thing is there are only a few of these cores running Linux out in the wild. This only works on UP systems. Reviewed-by: Colin Ian King <colin.king@canonical.com> Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Diffstat (limited to 'arch/arc')
-rw-r--r--arch/arc/include/asm/syscalls.h1
-rw-r--r--arch/arc/include/uapi/asm/unistd.h9
-rw-r--r--arch/arc/kernel/process.c33
3 files changed, 39 insertions, 4 deletions
diff --git a/arch/arc/include/asm/syscalls.h b/arch/arc/include/asm/syscalls.h
index e56f9fcc5581..772b67ca56e7 100644
--- a/arch/arc/include/asm/syscalls.h
+++ b/arch/arc/include/asm/syscalls.h
@@ -17,6 +17,7 @@ int sys_clone_wrapper(int, int, int, int, int);
17int sys_cacheflush(uint32_t, uint32_t uint32_t); 17int sys_cacheflush(uint32_t, uint32_t uint32_t);
18int sys_arc_settls(void *); 18int sys_arc_settls(void *);
19int sys_arc_gettls(void); 19int sys_arc_gettls(void);
20int sys_arc_usr_cmpxchg(int *, int, int);
20 21
21#include <asm-generic/syscalls.h> 22#include <asm-generic/syscalls.h>
22 23
diff --git a/arch/arc/include/uapi/asm/unistd.h b/arch/arc/include/uapi/asm/unistd.h
index 41fa2ec9e02c..9a34136d84b2 100644
--- a/arch/arc/include/uapi/asm/unistd.h
+++ b/arch/arc/include/uapi/asm/unistd.h
@@ -27,18 +27,19 @@
27 27
28#define NR_syscalls __NR_syscalls 28#define NR_syscalls __NR_syscalls
29 29
30/* Generic syscall (fs/filesystems.c - lost in asm-generic/unistd.h */
31#define __NR_sysfs (__NR_arch_specific_syscall + 3)
32
30/* ARC specific syscall */ 33/* ARC specific syscall */
31#define __NR_cacheflush (__NR_arch_specific_syscall + 0) 34#define __NR_cacheflush (__NR_arch_specific_syscall + 0)
32#define __NR_arc_settls (__NR_arch_specific_syscall + 1) 35#define __NR_arc_settls (__NR_arch_specific_syscall + 1)
33#define __NR_arc_gettls (__NR_arch_specific_syscall + 2) 36#define __NR_arc_gettls (__NR_arch_specific_syscall + 2)
37#define __NR_arc_usr_cmpxchg (__NR_arch_specific_syscall + 4)
34 38
35__SYSCALL(__NR_cacheflush, sys_cacheflush) 39__SYSCALL(__NR_cacheflush, sys_cacheflush)
36__SYSCALL(__NR_arc_settls, sys_arc_settls) 40__SYSCALL(__NR_arc_settls, sys_arc_settls)
37__SYSCALL(__NR_arc_gettls, sys_arc_gettls) 41__SYSCALL(__NR_arc_gettls, sys_arc_gettls)
38 42__SYSCALL(__NR_arc_usr_cmpxchg, sys_arc_usr_cmpxchg)
39
40/* Generic syscall (fs/filesystems.c - lost in asm-generic/unistd.h */
41#define __NR_sysfs (__NR_arch_specific_syscall + 3)
42__SYSCALL(__NR_sysfs, sys_sysfs) 43__SYSCALL(__NR_sysfs, sys_sysfs)
43 44
44#undef __SYSCALL 45#undef __SYSCALL
diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c
index be1972bd2729..59aa43cb146e 100644
--- a/arch/arc/kernel/process.c
+++ b/arch/arc/kernel/process.c
@@ -41,6 +41,39 @@ SYSCALL_DEFINE0(arc_gettls)
41 return task_thread_info(current)->thr_ptr; 41 return task_thread_info(current)->thr_ptr;
42} 42}
43 43
44SYSCALL_DEFINE3(arc_usr_cmpxchg, int *, uaddr, int, expected, int, new)
45{
46 int uval;
47 int ret;
48
49 /*
50 * This is only for old cores lacking LLOCK/SCOND, which by defintion
51 * can't possibly be SMP. Thus doesn't need to be SMP safe.
52 * And this also helps reduce the overhead for serializing in
53 * the UP case
54 */
55 WARN_ON_ONCE(IS_ENABLED(CONFIG_SMP));
56
57 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
58 return -EFAULT;
59
60 preempt_disable();
61
62 ret = __get_user(uval, uaddr);
63 if (ret)
64 goto done;
65
66 if (uval != expected)
67 ret = -EAGAIN;
68 else
69 ret = __put_user(new, uaddr);
70
71done:
72 preempt_enable();
73
74 return ret;
75}
76
44void arch_cpu_idle(void) 77void arch_cpu_idle(void)
45{ 78{
46 /* sleep, but enable all interrupts before committing */ 79 /* sleep, but enable all interrupts before committing */