diff options
| author | Ley Foon Tan <lftan@altera.com> | 2014-11-06 02:19:34 -0500 |
|---|---|---|
| committer | Ley Foon Tan <lftan@altera.com> | 2014-12-07 23:55:48 -0500 |
| commit | 00f634bc522dedc8418fb6d967a76cc4c10376a5 (patch) | |
| tree | 693a2b613bdbb2c6ed9401e8fd261548dc5bd538 /include | |
| parent | b2776bf7149bddd1f4161f14f79520f17fc1d71d (diff) | |
asm-generic: add generic futex for !CONFIG_SMP
Follow m68k futex implementation for !CONFIG_SMP.
Signed-off-by: Ley Foon Tan <lftan@altera.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'include')
| -rw-r--r-- | include/asm-generic/futex.h | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h index 01f227e14254..b59b5a52637e 100644 --- a/include/asm-generic/futex.h +++ b/include/asm-generic/futex.h | |||
| @@ -5,6 +5,119 @@ | |||
| 5 | #include <linux/uaccess.h> | 5 | #include <linux/uaccess.h> |
| 6 | #include <asm/errno.h> | 6 | #include <asm/errno.h> |
| 7 | 7 | ||
| 8 | #ifndef CONFIG_SMP | ||
| 9 | /* | ||
| 10 | * The following implementation only for uniprocessor machines. | ||
| 11 | * For UP, it's relies on the fact that pagefault_disable() also disables | ||
| 12 | * preemption to ensure mutual exclusion. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | /** | ||
| 17 | * futex_atomic_op_inuser() - Atomic arithmetic operation with constant | ||
| 18 | * argument and comparison of the previous | ||
| 19 | * futex value with another constant. | ||
| 20 | * | ||
| 21 | * @encoded_op: encoded operation to execute | ||
| 22 | * @uaddr: pointer to user space address | ||
| 23 | * | ||
| 24 | * Return: | ||
| 25 | * 0 - On success | ||
| 26 | * <0 - On error | ||
| 27 | */ | ||
| 28 | static inline int | ||
| 29 | futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) | ||
| 30 | { | ||
| 31 | int op = (encoded_op >> 28) & 7; | ||
| 32 | int cmp = (encoded_op >> 24) & 15; | ||
| 33 | int oparg = (encoded_op << 8) >> 20; | ||
| 34 | int cmparg = (encoded_op << 20) >> 20; | ||
| 35 | int oldval, ret; | ||
| 36 | u32 tmp; | ||
| 37 | |||
| 38 | if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) | ||
| 39 | oparg = 1 << oparg; | ||
| 40 | |||
| 41 | pagefault_disable(); | ||
| 42 | |||
| 43 | ret = -EFAULT; | ||
| 44 | if (unlikely(get_user(oldval, uaddr) != 0)) | ||
| 45 | goto out_pagefault_enable; | ||
| 46 | |||
| 47 | ret = 0; | ||
| 48 | tmp = oldval; | ||
| 49 | |||
| 50 | switch (op) { | ||
| 51 | case FUTEX_OP_SET: | ||
| 52 | tmp = oparg; | ||
| 53 | break; | ||
| 54 | case FUTEX_OP_ADD: | ||
| 55 | tmp += oparg; | ||
| 56 | break; | ||
| 57 | case FUTEX_OP_OR: | ||
| 58 | tmp |= oparg; | ||
| 59 | break; | ||
| 60 | case FUTEX_OP_ANDN: | ||
| 61 | tmp &= ~oparg; | ||
| 62 | break; | ||
| 63 | case FUTEX_OP_XOR: | ||
| 64 | tmp ^= oparg; | ||
| 65 | break; | ||
| 66 | default: | ||
| 67 | ret = -ENOSYS; | ||
| 68 | } | ||
| 69 | |||
| 70 | if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0)) | ||
| 71 | ret = -EFAULT; | ||
| 72 | |||
| 73 | out_pagefault_enable: | ||
| 74 | pagefault_enable(); | ||
| 75 | |||
| 76 | if (ret == 0) { | ||
| 77 | switch (cmp) { | ||
| 78 | case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; | ||
| 79 | case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; | ||
| 80 | case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; | ||
| 81 | case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; | ||
| 82 | case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; | ||
| 83 | case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; | ||
| 84 | default: ret = -ENOSYS; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | return ret; | ||
| 88 | } | ||
| 89 | |||
| 90 | /** | ||
| 91 | * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the | ||
| 92 | * uaddr with newval if the current value is | ||
| 93 | * oldval. | ||
| 94 | * @uval: pointer to store content of @uaddr | ||
| 95 | * @uaddr: pointer to user space address | ||
| 96 | * @oldval: old value | ||
| 97 | * @newval: new value to store to @uaddr | ||
| 98 | * | ||
| 99 | * Return: | ||
| 100 | * 0 - On success | ||
| 101 | * <0 - On error | ||
| 102 | */ | ||
| 103 | static inline int | ||
| 104 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | ||
| 105 | u32 oldval, u32 newval) | ||
| 106 | { | ||
| 107 | u32 val; | ||
| 108 | |||
| 109 | if (unlikely(get_user(val, uaddr) != 0)) | ||
| 110 | return -EFAULT; | ||
| 111 | |||
| 112 | if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) | ||
| 113 | return -EFAULT; | ||
| 114 | |||
| 115 | *uval = val; | ||
| 116 | |||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | #else | ||
| 8 | static inline int | 121 | static inline int |
| 9 | futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) | 122 | futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) |
| 10 | { | 123 | { |
| @@ -54,4 +167,5 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | |||
| 54 | return -ENOSYS; | 167 | return -ENOSYS; |
| 55 | } | 168 | } |
| 56 | 169 | ||
| 170 | #endif /* CONFIG_SMP */ | ||
| 57 | #endif | 171 | #endif |
