17153c3cbSHuacai Chen /* SPDX-License-Identifier: GPL-2.0 */ 27153c3cbSHuacai Chen /* 37153c3cbSHuacai Chen * Copyright (C) 2020-2022 Loongson Technology Corporation Limited 47153c3cbSHuacai Chen */ 57153c3cbSHuacai Chen #ifndef _ASM_FUTEX_H 67153c3cbSHuacai Chen #define _ASM_FUTEX_H 77153c3cbSHuacai Chen 87153c3cbSHuacai Chen #include <linux/futex.h> 97153c3cbSHuacai Chen #include <linux/uaccess.h> 107153c3cbSHuacai Chen #include <asm/barrier.h> 117153c3cbSHuacai Chen #include <asm/errno.h> 127153c3cbSHuacai Chen 137153c3cbSHuacai Chen #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \ 147153c3cbSHuacai Chen { \ 157153c3cbSHuacai Chen __asm__ __volatile__( \ 167153c3cbSHuacai Chen "1: ll.w %1, %4 # __futex_atomic_op\n" \ 177153c3cbSHuacai Chen " " insn " \n" \ 187153c3cbSHuacai Chen "2: sc.w $t0, %2 \n" \ 19d47b2dc8SWANG Xuerui " beqz $t0, 1b \n" \ 207153c3cbSHuacai Chen "3: \n" \ 217153c3cbSHuacai Chen " .section .fixup,\"ax\" \n" \ 227153c3cbSHuacai Chen "4: li.w %0, %6 \n" \ 237153c3cbSHuacai Chen " b 3b \n" \ 247153c3cbSHuacai Chen " .previous \n" \ 257153c3cbSHuacai Chen " .section __ex_table,\"a\" \n" \ 267153c3cbSHuacai Chen " "__UA_ADDR "\t1b, 4b \n" \ 277153c3cbSHuacai Chen " "__UA_ADDR "\t2b, 4b \n" \ 287153c3cbSHuacai Chen " .previous \n" \ 297153c3cbSHuacai Chen : "=r" (ret), "=&r" (oldval), \ 307153c3cbSHuacai Chen "=ZC" (*uaddr) \ 317153c3cbSHuacai Chen : "0" (0), "ZC" (*uaddr), "Jr" (oparg), \ 327153c3cbSHuacai Chen "i" (-EFAULT) \ 337153c3cbSHuacai Chen : "memory", "t0"); \ 347153c3cbSHuacai Chen } 357153c3cbSHuacai Chen 367153c3cbSHuacai Chen static inline int 377153c3cbSHuacai Chen arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr) 387153c3cbSHuacai Chen { 397153c3cbSHuacai Chen int oldval = 0, ret = 0; 407153c3cbSHuacai Chen 417153c3cbSHuacai Chen pagefault_disable(); 427153c3cbSHuacai Chen 437153c3cbSHuacai Chen switch (op) { 447153c3cbSHuacai Chen case FUTEX_OP_SET: 457153c3cbSHuacai Chen __futex_atomic_op("move $t0, %z5", ret, oldval, uaddr, oparg); 467153c3cbSHuacai Chen break; 477153c3cbSHuacai Chen case FUTEX_OP_ADD: 487153c3cbSHuacai Chen __futex_atomic_op("add.w $t0, %1, %z5", ret, oldval, uaddr, oparg); 497153c3cbSHuacai Chen break; 507153c3cbSHuacai Chen case FUTEX_OP_OR: 517153c3cbSHuacai Chen __futex_atomic_op("or $t0, %1, %z5", ret, oldval, uaddr, oparg); 527153c3cbSHuacai Chen break; 537153c3cbSHuacai Chen case FUTEX_OP_ANDN: 547153c3cbSHuacai Chen __futex_atomic_op("and $t0, %1, %z5", ret, oldval, uaddr, ~oparg); 557153c3cbSHuacai Chen break; 567153c3cbSHuacai Chen case FUTEX_OP_XOR: 577153c3cbSHuacai Chen __futex_atomic_op("xor $t0, %1, %z5", ret, oldval, uaddr, oparg); 587153c3cbSHuacai Chen break; 597153c3cbSHuacai Chen default: 607153c3cbSHuacai Chen ret = -ENOSYS; 617153c3cbSHuacai Chen } 627153c3cbSHuacai Chen 637153c3cbSHuacai Chen pagefault_enable(); 647153c3cbSHuacai Chen 657153c3cbSHuacai Chen if (!ret) 667153c3cbSHuacai Chen *oval = oldval; 677153c3cbSHuacai Chen 687153c3cbSHuacai Chen return ret; 697153c3cbSHuacai Chen } 707153c3cbSHuacai Chen 717153c3cbSHuacai Chen static inline int 727153c3cbSHuacai Chen futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) 737153c3cbSHuacai Chen { 747153c3cbSHuacai Chen int ret = 0; 757153c3cbSHuacai Chen u32 val = 0; 767153c3cbSHuacai Chen 777153c3cbSHuacai Chen if (!access_ok(uaddr, sizeof(u32))) 787153c3cbSHuacai Chen return -EFAULT; 797153c3cbSHuacai Chen 807153c3cbSHuacai Chen __asm__ __volatile__( 817153c3cbSHuacai Chen "# futex_atomic_cmpxchg_inatomic \n" 827153c3cbSHuacai Chen "1: ll.w %1, %3 \n" 837153c3cbSHuacai Chen " bne %1, %z4, 3f \n" 8457ce5d3eSWANG Xuerui " move $t0, %z5 \n" 857153c3cbSHuacai Chen "2: sc.w $t0, %2 \n" 86d47b2dc8SWANG Xuerui " beqz $t0, 1b \n" 877153c3cbSHuacai Chen "3: \n" 8846859ac8SHuacai Chen __WEAK_LLSC_MB 897153c3cbSHuacai Chen " .section .fixup,\"ax\" \n" 907153c3cbSHuacai Chen "4: li.d %0, %6 \n" 917153c3cbSHuacai Chen " b 3b \n" 927153c3cbSHuacai Chen " .previous \n" 937153c3cbSHuacai Chen " .section __ex_table,\"a\" \n" 947153c3cbSHuacai Chen " "__UA_ADDR "\t1b, 4b \n" 957153c3cbSHuacai Chen " "__UA_ADDR "\t2b, 4b \n" 967153c3cbSHuacai Chen " .previous \n" 97*f62b7626SJun Yi : "+r" (ret), "=&r" (val), "=ZC" (*uaddr) 98*f62b7626SJun Yi : "ZC" (*uaddr), "Jr" (oldval), "Jr" (newval), 997153c3cbSHuacai Chen "i" (-EFAULT) 1007153c3cbSHuacai Chen : "memory", "t0"); 1017153c3cbSHuacai Chen 1027153c3cbSHuacai Chen *uval = val; 1037153c3cbSHuacai Chen 1047153c3cbSHuacai Chen return ret; 1057153c3cbSHuacai Chen } 1067153c3cbSHuacai Chen 1077153c3cbSHuacai Chen #endif /* _ASM_FUTEX_H */ 108