18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2020 Loongson Technology Corporation Limited 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#ifndef _ASM_FUTEX_H 68c2ecf20Sopenharmony_ci#define _ASM_FUTEX_H 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/futex.h> 98c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 108c2ecf20Sopenharmony_ci#include <asm/asm-extable.h> 118c2ecf20Sopenharmony_ci#include <asm/barrier.h> 128c2ecf20Sopenharmony_ci#include <asm/errno.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ 158c2ecf20Sopenharmony_ci{ \ 168c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 178c2ecf20Sopenharmony_ci "1: ll.w %1, %4 # __futex_atomic_op\n" \ 188c2ecf20Sopenharmony_ci " " insn " \n" \ 198c2ecf20Sopenharmony_ci "2: sc.w $t0, %2 \n" \ 208c2ecf20Sopenharmony_ci " beq $t0, $zero, 1b \n" \ 218c2ecf20Sopenharmony_ci "3: \n" \ 228c2ecf20Sopenharmony_ci _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0) \ 238c2ecf20Sopenharmony_ci _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0) \ 248c2ecf20Sopenharmony_ci : "=r" (ret), "=&r" (oldval), \ 258c2ecf20Sopenharmony_ci "=ZC" (*uaddr) \ 268c2ecf20Sopenharmony_ci : "0" (0), "ZC" (*uaddr), "Jr" (oparg) \ 278c2ecf20Sopenharmony_ci : "memory", "t0"); \ 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic inline int 318c2ecf20Sopenharmony_ciarch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci int oldval = 0, ret = 0; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci pagefault_disable(); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci switch (op) { 388c2ecf20Sopenharmony_ci case FUTEX_OP_SET: 398c2ecf20Sopenharmony_ci __futex_atomic_op("move $t0, %z5", ret, oldval, uaddr, oparg); 408c2ecf20Sopenharmony_ci break; 418c2ecf20Sopenharmony_ci case FUTEX_OP_ADD: 428c2ecf20Sopenharmony_ci __futex_atomic_op("add.w $t0, %1, %z5", ret, oldval, uaddr, oparg); 438c2ecf20Sopenharmony_ci break; 448c2ecf20Sopenharmony_ci case FUTEX_OP_OR: 458c2ecf20Sopenharmony_ci __futex_atomic_op("or $t0, %1, %z5", ret, oldval, uaddr, oparg); 468c2ecf20Sopenharmony_ci break; 478c2ecf20Sopenharmony_ci case FUTEX_OP_ANDN: 488c2ecf20Sopenharmony_ci __futex_atomic_op("and $t0, %1, %z5", ret, oldval, uaddr, ~oparg); 498c2ecf20Sopenharmony_ci break; 508c2ecf20Sopenharmony_ci case FUTEX_OP_XOR: 518c2ecf20Sopenharmony_ci __futex_atomic_op("xor $t0, %1, %z5", ret, oldval, uaddr, oparg); 528c2ecf20Sopenharmony_ci break; 538c2ecf20Sopenharmony_ci default: 548c2ecf20Sopenharmony_ci ret = -ENOSYS; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci pagefault_enable(); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (!ret) 608c2ecf20Sopenharmony_ci *oval = oldval; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci return ret; 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic inline int 668c2ecf20Sopenharmony_cifutex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci int ret = 0; 698c2ecf20Sopenharmony_ci u32 val = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (!access_ok(uaddr, sizeof(u32))) 728c2ecf20Sopenharmony_ci return -EFAULT; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci __asm__ __volatile__( 758c2ecf20Sopenharmony_ci "# futex_atomic_cmpxchg_inatomic \n" 768c2ecf20Sopenharmony_ci "1: ll.w %1, %3 \n" 778c2ecf20Sopenharmony_ci " bne %1, %z4, 3f \n" 788c2ecf20Sopenharmony_ci " or $t0, %z5, $zero \n" 798c2ecf20Sopenharmony_ci "2: sc.w $t0, %2 \n" 808c2ecf20Sopenharmony_ci " beq $zero, $t0, 1b \n" 818c2ecf20Sopenharmony_ci "3: \n" 828c2ecf20Sopenharmony_ci __WEAK_LLSC_MB 838c2ecf20Sopenharmony_ci _ASM_EXTABLE_UACCESS_ERR(1b, 3b, %0) 848c2ecf20Sopenharmony_ci _ASM_EXTABLE_UACCESS_ERR(2b, 3b, %0) 858c2ecf20Sopenharmony_ci : "+r" (ret), "=&r" (val), "=ZC" (*uaddr) 868c2ecf20Sopenharmony_ci : "ZC" (*uaddr), "Jr" (oldval), "Jr" (newval) 878c2ecf20Sopenharmony_ci : "memory", "t0"); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci *uval = val; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci return ret; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#endif /* _ASM_FUTEX_H */ 95