|
@@ -84,7 +84,33 @@ static inline int futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
|
|
|
static inline int
|
|
|
futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
|
|
|
{
|
|
|
- return -ENOSYS;
|
|
|
+ int prev;
|
|
|
+
|
|
|
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ __asm__ __volatile__ (
|
|
|
+ LWSYNC_ON_SMP
|
|
|
+"1: lwarx %0,0,%2 # futex_atomic_cmpxchg_inatomic\n\
|
|
|
+ cmpw 0,%0,%3\n\
|
|
|
+ bne- 3f\n"
|
|
|
+ PPC405_ERR77(0,%2)
|
|
|
+"2: stwcx. %4,0,%2\n\
|
|
|
+ bne- 1b\n"
|
|
|
+ ISYNC_ON_SMP
|
|
|
+"3: .section .fixup,\"ax\"\n\
|
|
|
+4: li %0,%5\n\
|
|
|
+ b 3b\n\
|
|
|
+ .previous\n\
|
|
|
+ .section __ex_table,\"a\"\n\
|
|
|
+ .align 3\n\
|
|
|
+ " PPC_LONG "1b,4b,2b,4b\n\
|
|
|
+ .previous" \
|
|
|
+ : "=&r" (prev), "+m" (*uaddr)
|
|
|
+ : "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT)
|
|
|
+ : "cc", "memory");
|
|
|
+
|
|
|
+ return prev;
|
|
|
}
|
|
|
|
|
|
#endif /* __KERNEL__ */
|