18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci// Copyright (C) 2005-2017 Andes Technology Corporation 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#ifndef __NDS32_FUTEX_H__ 58c2ecf20Sopenharmony_ci#define __NDS32_FUTEX_H__ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/futex.h> 88c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 98c2ecf20Sopenharmony_ci#include <asm/errno.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define __futex_atomic_ex_table(err_reg) \ 128c2ecf20Sopenharmony_ci " .pushsection __ex_table,\"a\"\n" \ 138c2ecf20Sopenharmony_ci " .align 3\n" \ 148c2ecf20Sopenharmony_ci " .long 1b, 4f\n" \ 158c2ecf20Sopenharmony_ci " .long 2b, 4f\n" \ 168c2ecf20Sopenharmony_ci " .popsection\n" \ 178c2ecf20Sopenharmony_ci " .pushsection .fixup,\"ax\"\n" \ 188c2ecf20Sopenharmony_ci "4: move %0, " err_reg "\n" \ 198c2ecf20Sopenharmony_ci " b 3b\n" \ 208c2ecf20Sopenharmony_ci " .popsection" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ 238c2ecf20Sopenharmony_ci smp_mb(); \ 248c2ecf20Sopenharmony_ci asm volatile( \ 258c2ecf20Sopenharmony_ci " movi $ta, #0\n" \ 268c2ecf20Sopenharmony_ci "1: llw %1, [%2+$ta]\n" \ 278c2ecf20Sopenharmony_ci " " insn "\n" \ 288c2ecf20Sopenharmony_ci "2: scw %0, [%2+$ta]\n" \ 298c2ecf20Sopenharmony_ci " beqz %0, 1b\n" \ 308c2ecf20Sopenharmony_ci " movi %0, #0\n" \ 318c2ecf20Sopenharmony_ci "3:\n" \ 328c2ecf20Sopenharmony_ci __futex_atomic_ex_table("%4") \ 338c2ecf20Sopenharmony_ci : "=&r" (ret), "=&r" (oldval) \ 348c2ecf20Sopenharmony_ci : "r" (uaddr), "r" (oparg), "i" (-EFAULT) \ 358c2ecf20Sopenharmony_ci : "cc", "memory") 368c2ecf20Sopenharmony_cistatic inline int 378c2ecf20Sopenharmony_cifutex_atomic_cmpxchg_inatomic(u32 * uval, u32 __user * uaddr, 388c2ecf20Sopenharmony_ci u32 oldval, u32 newval) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci int ret = 0; 418c2ecf20Sopenharmony_ci u32 val, tmp, flags; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (!access_ok(uaddr, sizeof(u32))) 448c2ecf20Sopenharmony_ci return -EFAULT; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci smp_mb(); 478c2ecf20Sopenharmony_ci asm volatile (" movi $ta, #0\n" 488c2ecf20Sopenharmony_ci "1: llw %1, [%6 + $ta]\n" 498c2ecf20Sopenharmony_ci " sub %3, %1, %4\n" 508c2ecf20Sopenharmony_ci " cmovz %2, %5, %3\n" 518c2ecf20Sopenharmony_ci " cmovn %2, %1, %3\n" 528c2ecf20Sopenharmony_ci "2: scw %2, [%6 + $ta]\n" 538c2ecf20Sopenharmony_ci " beqz %2, 1b\n" 548c2ecf20Sopenharmony_ci "3:\n " __futex_atomic_ex_table("%7") 558c2ecf20Sopenharmony_ci :"+&r"(ret), "=&r"(val), "=&r"(tmp), "=&r"(flags) 568c2ecf20Sopenharmony_ci :"r"(oldval), "r"(newval), "r"(uaddr), "i"(-EFAULT) 578c2ecf20Sopenharmony_ci :"$ta", "memory"); 588c2ecf20Sopenharmony_ci smp_mb(); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci *uval = val; 618c2ecf20Sopenharmony_ci return ret; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic inline int 658c2ecf20Sopenharmony_ciarch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci int oldval = 0, ret; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci if (!access_ok(uaddr, sizeof(u32))) 708c2ecf20Sopenharmony_ci return -EFAULT; 718c2ecf20Sopenharmony_ci switch (op) { 728c2ecf20Sopenharmony_ci case FUTEX_OP_SET: 738c2ecf20Sopenharmony_ci __futex_atomic_op("move %0, %3", ret, oldval, tmp, uaddr, 748c2ecf20Sopenharmony_ci oparg); 758c2ecf20Sopenharmony_ci break; 768c2ecf20Sopenharmony_ci case FUTEX_OP_ADD: 778c2ecf20Sopenharmony_ci __futex_atomic_op("add %0, %1, %3", ret, oldval, tmp, uaddr, 788c2ecf20Sopenharmony_ci oparg); 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci case FUTEX_OP_OR: 818c2ecf20Sopenharmony_ci __futex_atomic_op("or %0, %1, %3", ret, oldval, tmp, uaddr, 828c2ecf20Sopenharmony_ci oparg); 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci case FUTEX_OP_ANDN: 858c2ecf20Sopenharmony_ci __futex_atomic_op("and %0, %1, %3", ret, oldval, tmp, uaddr, 868c2ecf20Sopenharmony_ci ~oparg); 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci case FUTEX_OP_XOR: 898c2ecf20Sopenharmony_ci __futex_atomic_op("xor %0, %1, %3", ret, oldval, tmp, uaddr, 908c2ecf20Sopenharmony_ci oparg); 918c2ecf20Sopenharmony_ci break; 928c2ecf20Sopenharmony_ci default: 938c2ecf20Sopenharmony_ci ret = -ENOSYS; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!ret) 978c2ecf20Sopenharmony_ci *oval = oldval; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return ret; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci#endif /* __NDS32_FUTEX_H__ */ 102