| /* SPDX-License-Identifier: GPL-2.0 */ | 
 | #ifndef _ASM_GENERIC_FUTEX_H | 
 | #define _ASM_GENERIC_FUTEX_H | 
 |  | 
 | #include <linux/futex.h> | 
 | #include <linux/uaccess.h> | 
 | #include <asm/errno.h> | 
 |  | 
 | #ifndef CONFIG_SMP | 
 | /* | 
 |  * The following implementation only for uniprocessor machines. | 
 |  * It relies on preempt_disable() ensuring mutual exclusion. | 
 |  * | 
 |  */ | 
 |  | 
 | /** | 
 |  * arch_futex_atomic_op_inuser() - Atomic arithmetic operation with constant | 
 |  *			  argument and comparison of the previous | 
 |  *			  futex value with another constant. | 
 |  * | 
 |  * @encoded_op:	encoded operation to execute | 
 |  * @uaddr:	pointer to user space address | 
 |  * | 
 |  * Return: | 
 |  * 0 - On success | 
 |  * -EFAULT - User access resulted in a page fault | 
 |  * -EAGAIN - Atomic operation was unable to complete due to contention | 
 |  * -ENOSYS - Operation not supported | 
 |  */ | 
 | static inline int | 
 | arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) | 
 | { | 
 | 	int oldval, ret; | 
 | 	u32 tmp; | 
 |  | 
 | 	preempt_disable(); | 
 | 	pagefault_disable(); | 
 |  | 
 | 	ret = -EFAULT; | 
 | 	if (unlikely(get_user(oldval, uaddr) != 0)) | 
 | 		goto out_pagefault_enable; | 
 |  | 
 | 	ret = 0; | 
 | 	tmp = oldval; | 
 |  | 
 | 	switch (op) { | 
 | 	case FUTEX_OP_SET: | 
 | 		tmp = oparg; | 
 | 		break; | 
 | 	case FUTEX_OP_ADD: | 
 | 		tmp += oparg; | 
 | 		break; | 
 | 	case FUTEX_OP_OR: | 
 | 		tmp |= oparg; | 
 | 		break; | 
 | 	case FUTEX_OP_ANDN: | 
 | 		tmp &= ~oparg; | 
 | 		break; | 
 | 	case FUTEX_OP_XOR: | 
 | 		tmp ^= oparg; | 
 | 		break; | 
 | 	default: | 
 | 		ret = -ENOSYS; | 
 | 	} | 
 |  | 
 | 	if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0)) | 
 | 		ret = -EFAULT; | 
 |  | 
 | out_pagefault_enable: | 
 | 	pagefault_enable(); | 
 | 	preempt_enable(); | 
 |  | 
 | 	if (ret == 0) | 
 | 		*oval = oldval; | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | /** | 
 |  * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the | 
 |  *				uaddr with newval if the current value is | 
 |  *				oldval. | 
 |  * @uval:	pointer to store content of @uaddr | 
 |  * @uaddr:	pointer to user space address | 
 |  * @oldval:	old value | 
 |  * @newval:	new value to store to @uaddr | 
 |  * | 
 |  * Return: | 
 |  * 0 - On success | 
 |  * -EFAULT - User access resulted in a page fault | 
 |  * -EAGAIN - Atomic operation was unable to complete due to contention | 
 |  * -ENOSYS - Function not implemented (only if !HAVE_FUTEX_CMPXCHG) | 
 |  */ | 
 | static inline int | 
 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | 
 | 			      u32 oldval, u32 newval) | 
 | { | 
 | 	u32 val; | 
 |  | 
 | 	preempt_disable(); | 
 | 	if (unlikely(get_user(val, uaddr) != 0)) { | 
 | 		preempt_enable(); | 
 | 		return -EFAULT; | 
 | 	} | 
 |  | 
 | 	if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) { | 
 | 		preempt_enable(); | 
 | 		return -EFAULT; | 
 | 	} | 
 |  | 
 | 	*uval = val; | 
 | 	preempt_enable(); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | #else | 
 | static inline int | 
 | arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr) | 
 | { | 
 | 	int oldval = 0, ret; | 
 |  | 
 | 	pagefault_disable(); | 
 |  | 
 | 	switch (op) { | 
 | 	case FUTEX_OP_SET: | 
 | 	case FUTEX_OP_ADD: | 
 | 	case FUTEX_OP_OR: | 
 | 	case FUTEX_OP_ANDN: | 
 | 	case FUTEX_OP_XOR: | 
 | 	default: | 
 | 		ret = -ENOSYS; | 
 | 	} | 
 |  | 
 | 	pagefault_enable(); | 
 |  | 
 | 	if (!ret) | 
 | 		*oval = oldval; | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | static inline int | 
 | futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, | 
 | 			      u32 oldval, u32 newval) | 
 | { | 
 | 	return -ENOSYS; | 
 | } | 
 |  | 
 | #endif /* CONFIG_SMP */ | 
 | #endif |