1/* SPDX-License-Identifier: GPL-2.0 */ 2// Copyright (C) 2005-2017 Andes Technology Corporation 3 4#ifndef __NDS32_FUTEX_H__ 5#define __NDS32_FUTEX_H__ 6 7#include <linux/futex.h> 8#include <linux/uaccess.h> 9#include <asm/errno.h> 10 11#define __futex_atomic_ex_table(err_reg) \ 12 " .pushsection __ex_table,\"a\"\n" \ 13 " .align 3\n" \ 14 " .long 1b, 4f\n" \ 15 " .long 2b, 4f\n" \ 16 " .popsection\n" \ 17 " .pushsection .fixup,\"ax\"\n" \ 18 "4: move %0, " err_reg "\n" \ 19 " b 3b\n" \ 20 " .popsection" 21 22#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ 23 smp_mb(); \ 24 asm volatile( \ 25 " movi $ta, #0\n" \ 26 "1: llw %1, [%2+$ta]\n" \ 27 " " insn "\n" \ 28 "2: scw %0, [%2+$ta]\n" \ 29 " beqz %0, 1b\n" \ 30 " movi %0, #0\n" \ 31 "3:\n" \ 32 __futex_atomic_ex_table("%4") \ 33 : "=&r" (ret), "=&r" (oldval) \ 34 : "r" (uaddr), "r" (oparg), "i" (-EFAULT) \ 35 : "cc", "memory") 36static inline int 37futex_atomic_cmpxchg_inatomic(u32 * uval, u32 __user * uaddr, 38 u32 oldval, u32 newval) 39{ 40 int ret = 0; 41 u32 val, tmp, flags; 42 43 if (!access_ok(uaddr, sizeof(u32))) 44 return -EFAULT; 45 46 smp_mb(); 47 asm volatile (" movi $ta, #0\n" 48 "1: llw %1, [%6 + $ta]\n" 49 " sub %3, %1, %4\n" 50 " cmovz %2, %5, %3\n" 51 " cmovn %2, %1, %3\n" 52 "2: scw %2, [%6 + $ta]\n" 53 " beqz %2, 1b\n" 54 "3:\n " __futex_atomic_ex_table("%7") 55 :"+&r"(ret), "=&r"(val), "=&r"(tmp), "=&r"(flags) 56 :"r"(oldval), "r"(newval), "r"(uaddr), "i"(-EFAULT) 57 :"$ta", "memory"); 58 smp_mb(); 59 60 *uval = val; 61 return ret; 62} 63 64static inline int 65arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) 66{ 67 int oldval = 0, ret; 68 69 if (!access_ok(uaddr, sizeof(u32))) 70 return -EFAULT; 71 switch (op) { 72 case FUTEX_OP_SET: 73 __futex_atomic_op("move %0, %3", ret, oldval, tmp, uaddr, 74 oparg); 75 break; 76 case FUTEX_OP_ADD: 77 __futex_atomic_op("add %0, %1, %3", ret, oldval, tmp, uaddr, 78 oparg); 79 break; 80 case FUTEX_OP_OR: 81 __futex_atomic_op("or %0, %1, %3", ret, oldval, tmp, uaddr, 82 oparg); 83 break; 84 case FUTEX_OP_ANDN: 85 __futex_atomic_op("and %0, %1, %3", ret, oldval, tmp, uaddr, 86 ~oparg); 87 break; 88 case FUTEX_OP_XOR: 89 __futex_atomic_op("xor %0, %1, %3", ret, oldval, tmp, uaddr, 90 oparg); 91 break; 92 default: 93 ret = -ENOSYS; 94 } 95 96 if (!ret) 97 *oval = oldval; 98 99 return ret; 100} 101#endif /* __NDS32_FUTEX_H__ */ 102