linux/arch/xtensa/include/asm/futex.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-only */
   2/*
   3 * Atomic futex routines
   4 *
   5 * Based on the PowerPC implementataion
   6 *
   7 * Copyright (C) 2013 TangoTec Ltd.
   8 *
   9 * Baruch Siach <baruch@tkos.co.il>
  10 */
  11
  12#ifndef _ASM_XTENSA_FUTEX_H
  13#define _ASM_XTENSA_FUTEX_H
  14
  15#include <linux/futex.h>
  16#include <linux/uaccess.h>
  17#include <linux/errno.h>
  18
  19#if XCHAL_HAVE_EXCLUSIVE
  20#define __futex_atomic_op(insn, ret, old, uaddr, arg)   \
  21        __asm__ __volatile(                             \
  22        "1:     l32ex   %[oldval], %[addr]\n"           \
  23                insn "\n"                               \
  24        "2:     s32ex   %[newval], %[addr]\n"           \
  25        "       getex   %[newval]\n"                    \
  26        "       beqz    %[newval], 1b\n"                \
  27        "       movi    %[newval], 0\n"                 \
  28        "3:\n"                                          \
  29        "       .section .fixup,\"ax\"\n"               \
  30        "       .align 4\n"                             \
  31        "       .literal_position\n"                    \
  32        "5:     movi    %[oldval], 3b\n"                \
  33        "       movi    %[newval], %[fault]\n"          \
  34        "       jx      %[oldval]\n"                    \
  35        "       .previous\n"                            \
  36        "       .section __ex_table,\"a\"\n"            \
  37        "       .long 1b, 5b, 2b, 5b\n"                 \
  38        "       .previous\n"                            \
  39        : [oldval] "=&r" (old), [newval] "=&r" (ret)    \
  40        : [addr] "r" (uaddr), [oparg] "r" (arg),        \
  41          [fault] "I" (-EFAULT)                         \
  42        : "memory")
  43#elif XCHAL_HAVE_S32C1I
  44#define __futex_atomic_op(insn, ret, old, uaddr, arg)   \
  45        __asm__ __volatile(                             \
  46        "1:     l32i    %[oldval], %[mem]\n"            \
  47                insn "\n"                               \
  48        "       wsr     %[oldval], scompare1\n"         \
  49        "2:     s32c1i  %[newval], %[mem]\n"            \
  50        "       bne     %[newval], %[oldval], 1b\n"     \
  51        "       movi    %[newval], 0\n"                 \
  52        "3:\n"                                          \
  53        "       .section .fixup,\"ax\"\n"               \
  54        "       .align 4\n"                             \
  55        "       .literal_position\n"                    \
  56        "5:     movi    %[oldval], 3b\n"                \
  57        "       movi    %[newval], %[fault]\n"          \
  58        "       jx      %[oldval]\n"                    \
  59        "       .previous\n"                            \
  60        "       .section __ex_table,\"a\"\n"            \
  61        "       .long 1b, 5b, 2b, 5b\n"                 \
  62        "       .previous\n"                            \
  63        : [oldval] "=&r" (old), [newval] "=&r" (ret),   \
  64          [mem] "+m" (*(uaddr))                         \
  65        : [oparg] "r" (arg), [fault] "I" (-EFAULT)      \
  66        : "memory")
  67#endif
  68
  69static inline int arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
  70                u32 __user *uaddr)
  71{
  72#if XCHAL_HAVE_S32C1I || XCHAL_HAVE_EXCLUSIVE
  73        int oldval = 0, ret;
  74
  75        if (!access_ok(uaddr, sizeof(u32)))
  76                return -EFAULT;
  77
  78        switch (op) {
  79        case FUTEX_OP_SET:
  80                __futex_atomic_op("mov %[newval], %[oparg]",
  81                                  ret, oldval, uaddr, oparg);
  82                break;
  83        case FUTEX_OP_ADD:
  84                __futex_atomic_op("add %[newval], %[oldval], %[oparg]",
  85                                  ret, oldval, uaddr, oparg);
  86                break;
  87        case FUTEX_OP_OR:
  88                __futex_atomic_op("or %[newval], %[oldval], %[oparg]",
  89                                  ret, oldval, uaddr, oparg);
  90                break;
  91        case FUTEX_OP_ANDN:
  92                __futex_atomic_op("and %[newval], %[oldval], %[oparg]",
  93                                  ret, oldval, uaddr, ~oparg);
  94                break;
  95        case FUTEX_OP_XOR:
  96                __futex_atomic_op("xor %[newval], %[oldval], %[oparg]",
  97                                  ret, oldval, uaddr, oparg);
  98                break;
  99        default:
 100                ret = -ENOSYS;
 101        }
 102
 103        if (!ret)
 104                *oval = oldval;
 105
 106        return ret;
 107#else
 108        return -ENOSYS;
 109#endif
 110}
 111
 112static inline int
 113futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 114                              u32 oldval, u32 newval)
 115{
 116#if XCHAL_HAVE_S32C1I || XCHAL_HAVE_EXCLUSIVE
 117        unsigned long tmp;
 118        int ret = 0;
 119
 120        if (!access_ok(uaddr, sizeof(u32)))
 121                return -EFAULT;
 122
 123        __asm__ __volatile__ (
 124        "       # futex_atomic_cmpxchg_inatomic\n"
 125#if XCHAL_HAVE_EXCLUSIVE
 126        "1:     l32ex   %[tmp], %[addr]\n"
 127        "       s32i    %[tmp], %[uval], 0\n"
 128        "       bne     %[tmp], %[oldval], 2f\n"
 129        "       mov     %[tmp], %[newval]\n"
 130        "3:     s32ex   %[tmp], %[addr]\n"
 131        "       getex   %[tmp]\n"
 132        "       beqz    %[tmp], 1b\n"
 133#elif XCHAL_HAVE_S32C1I
 134        "       wsr     %[oldval], scompare1\n"
 135        "1:     s32c1i  %[newval], %[addr], 0\n"
 136        "       s32i    %[newval], %[uval], 0\n"
 137#endif
 138        "2:\n"
 139        "       .section .fixup,\"ax\"\n"
 140        "       .align 4\n"
 141        "       .literal_position\n"
 142        "4:     movi    %[tmp], 2b\n"
 143        "       movi    %[ret], %[fault]\n"
 144        "       jx      %[tmp]\n"
 145        "       .previous\n"
 146        "       .section __ex_table,\"a\"\n"
 147        "       .long 1b, 4b\n"
 148#if XCHAL_HAVE_EXCLUSIVE
 149        "       .long 3b, 4b\n"
 150#endif
 151        "       .previous\n"
 152        : [ret] "+r" (ret), [newval] "+r" (newval), [tmp] "=&r" (tmp)
 153        : [addr] "r" (uaddr), [oldval] "r" (oldval), [uval] "r" (uval),
 154          [fault] "I" (-EFAULT)
 155        : "memory");
 156
 157        return ret;
 158#else
 159        return -ENOSYS;
 160#endif
 161}
 162
 163#endif /* _ASM_XTENSA_FUTEX_H */
 164