1515#include <asm/assembler.h>
1616#include <asm/errno.h>
1717
18- #ifdef CONFIG_ARC_HAS_LLSC
18+ #ifdef CONFIG_ARC_HAS_ATLD
19+
20+ #define __futex_atomic_op (insn , ret , oldval , uaddr , oparg )\
21+ \
22+ smp_mb(); \
23+ __asm__ __volatile__( \
24+ " mov %1, %3 \n" \
25+ "1: \n" \
26+ insn "\n" \
27+ " mov %0, 0 \n" \
28+ "2: \n" \
29+ " .section .fixup,\"ax\" \n" \
30+ " .align 4 \n" \
31+ "3: mov %0, %4 \n" \
32+ " b 2b \n" \
33+ " .previous \n" \
34+ " .section __ex_table,\"a\" \n" \
35+ " .align " REGSZASM " \n" \
36+ " " ARC_PTR " 1b, 3b \n" \
37+ " .previous \n" \
38+ \
39+ : "=&r" (ret), "=&r" (oldval) \
40+ : "r" (uaddr), "r" (oparg), "ir" (-EFAULT) \
41+ : "cc", "memory"); \
42+ smp_mb() \
43+
44+ #elif defined(CONFIG_ARC_HAS_LLSC )
1945
2046#define __futex_atomic_op (insn , ret , oldval , uaddr , oparg )\
2147 \
7298
7399#endif
74100
101+ #ifdef CONFIG_ARC_HAS_ATLD
102+ #define ARC_OP_SET "ex %1, [%2]"
103+ #define ARC_OP_ADD "atld.add %1, [%2]"
104+ #define ARC_OP_OR "atld.or %1, [%2]"
105+ #define ARC_OP_ANDN "atld.and %1, [%2]"
106+ #define ARC_OP_XOR "atld.xor %1, [%2]"
107+ #define ARC_OPARG_ANDN ~oparg
108+ #else /* !CONFIG_ARC_HAS_ATLD */
109+ #define ARC_OP_SET "mov %0, %3"
110+ #define ARC_OP_ADD "add %0, %1, %3"
111+ #define ARC_OP_OR "or %0, %1, %3"
112+ #define ARC_OP_ANDN "bic %0, %1, %3"
113+ #define ARC_OP_XOR "xor %0, %1, %3"
114+ #define ARC_OPARG_ANDN oparg
115+ #endif
116+
75117static inline int arch_futex_atomic_op_inuser (int op , int oparg , int * oval ,
76118 u32 __user * uaddr )
77119{
@@ -80,32 +122,32 @@ static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
80122 if (!access_ok (uaddr , sizeof (u32 )))
81123 return - EFAULT ;
82124
83- #ifndef CONFIG_ARC_HAS_LLSC
125+ #if !defined( CONFIG_ARC_HAS_LLSC ) && !defined( CONFIG_ARC_HAS_ATLD )
84126 preempt_disable (); /* to guarantee atomic r-m-w of futex op */
85127#endif
86128
87129 switch (op ) {
88130 case FUTEX_OP_SET :
89- __futex_atomic_op ("mov %0, %3" , ret , oldval , uaddr , oparg );
131+ __futex_atomic_op (ARC_OP_SET , ret , oldval , uaddr , oparg );
90132 break ;
91133 case FUTEX_OP_ADD :
92134 /* oldval = *uaddr; *uaddr += oparg ; ret = *uaddr */
93- __futex_atomic_op ("add %0, %1, %3" , ret , oldval , uaddr , oparg );
135+ __futex_atomic_op (ARC_OP_ADD , ret , oldval , uaddr , oparg );
94136 break ;
95137 case FUTEX_OP_OR :
96- __futex_atomic_op ("or %0, %1, %3" , ret , oldval , uaddr , oparg );
138+ __futex_atomic_op (ARC_OP_OR , ret , oldval , uaddr , oparg );
97139 break ;
98140 case FUTEX_OP_ANDN :
99- __futex_atomic_op ("bic %0, %1, %3" , ret , oldval , uaddr , oparg );
141+ __futex_atomic_op (ARC_OP_ANDN , ret , oldval , uaddr , ARC_OPARG_ANDN );
100142 break ;
101143 case FUTEX_OP_XOR :
102- __futex_atomic_op ("xor %0, %1, %3" , ret , oldval , uaddr , oparg );
144+ __futex_atomic_op (ARC_OP_XOR , ret , oldval , uaddr , oparg );
103145 break ;
104146 default :
105147 ret = - ENOSYS ;
106148 }
107149
108- #ifndef CONFIG_ARC_HAS_LLSC
150+ #if !defined( CONFIG_ARC_HAS_LLSC ) && !defined( CONFIG_ARC_HAS_ATLD )
109151 preempt_enable ();
110152#endif
111153
0 commit comments