^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0-only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Vineetg: August 2010: From Android kernel work
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #ifndef _ASM_FUTEX_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #define _ASM_FUTEX_H
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/futex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/preempt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <asm/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #ifdef CONFIG_ARC_HAS_LLSC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) smp_mb(); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) __asm__ __volatile__( \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) "1: llock %1, [%2] \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) insn "\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) "2: scond %0, [%2] \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) " bnz 1b \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) " mov %0, 0 \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) "3: \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) " .section .fixup,\"ax\" \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) " .align 4 \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) "4: mov %0, %4 \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) " j 3b \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) " .previous \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) " .section __ex_table,\"a\" \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) " .align 4 \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) " .word 1b, 4b \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) " .word 2b, 4b \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) " .previous \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) : "=&r" (ret), "=&r" (oldval) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) : "r" (uaddr), "r" (oparg), "ir" (-EFAULT) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) : "cc", "memory"); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) smp_mb() \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #else /* !CONFIG_ARC_HAS_LLSC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg)\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) smp_mb(); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) __asm__ __volatile__( \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) "1: ld %1, [%2] \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) insn "\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) "2: st %0, [%2] \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) " mov %0, 0 \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) "3: \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) " .section .fixup,\"ax\" \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) " .align 4 \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) "4: mov %0, %4 \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) " j 3b \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) " .previous \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) " .section __ex_table,\"a\" \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) " .align 4 \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) " .word 1b, 4b \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) " .word 2b, 4b \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) " .previous \n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) : "=&r" (ret), "=&r" (oldval) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) : "r" (uaddr), "r" (oparg), "ir" (-EFAULT) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) : "cc", "memory"); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) smp_mb() \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) u32 __user *uaddr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) int oldval = 0, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (!access_ok(uaddr, sizeof(u32)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #ifndef CONFIG_ARC_HAS_LLSC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) preempt_disable(); /* to guarantee atomic r-m-w of futex op */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) switch (op) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) case FUTEX_OP_SET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) __futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) case FUTEX_OP_ADD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /* oldval = *uaddr; *uaddr += oparg ; ret = *uaddr */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) __futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) case FUTEX_OP_OR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) __futex_atomic_op("or %0, %1, %3", ret, oldval, uaddr, oparg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) case FUTEX_OP_ANDN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) __futex_atomic_op("bic %0, %1, %3", ret, oldval, uaddr, oparg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) case FUTEX_OP_XOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) __futex_atomic_op("xor %0, %1, %3", ret, oldval, uaddr, oparg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) ret = -ENOSYS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #ifndef CONFIG_ARC_HAS_LLSC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) preempt_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) *oval = oldval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * cmpxchg of futex (pagefaults disabled by caller)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * Return 0 for success, -EFAULT otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static inline int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 expval,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) u32 newval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) u32 existval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (!access_ok(uaddr, sizeof(u32)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return -EFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) #ifndef CONFIG_ARC_HAS_LLSC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) preempt_disable(); /* to guarantee atomic r-m-w of futex op */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) smp_mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) __asm__ __volatile__(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #ifdef CONFIG_ARC_HAS_LLSC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) "1: llock %1, [%4] \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) " brne %1, %2, 3f \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) "2: scond %3, [%4] \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) " bnz 1b \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) "1: ld %1, [%4] \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) " brne %1, %2, 3f \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) "2: st %3, [%4] \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) "3: \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) " .section .fixup,\"ax\" \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) "4: mov %0, %5 \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) " j 3b \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) " .previous \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) " .section __ex_table,\"a\" \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) " .align 4 \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) " .word 1b, 4b \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) " .word 2b, 4b \n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) " .previous\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) : "+&r"(ret), "=&r"(existval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) : "r"(expval), "r"(newval), "r"(uaddr), "ir"(-EFAULT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) : "cc", "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) smp_mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) #ifndef CONFIG_ARC_HAS_LLSC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) preempt_enable();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) *uval = existval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) #endif