linux/arch/openrisc/include/asm/futex.h
<<
>>
Prefs
   1#ifndef __ASM_OPENRISC_FUTEX_H
   2#define __ASM_OPENRISC_FUTEX_H
   3
   4#ifdef __KERNEL__
   5
   6#include <linux/futex.h>
   7#include <linux/uaccess.h>
   8#include <asm/errno.h>
   9
  10#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
  11({                                                              \
  12        __asm__ __volatile__ (                                  \
  13                "1:     l.lwa   %0, %2                  \n"     \
  14                        insn                            "\n"    \
  15                "2:     l.swa   %2, %1                  \n"     \
  16                "       l.bnf   1b                      \n"     \
  17                "        l.ori  %1, r0, 0               \n"     \
  18                "3:                                     \n"     \
  19                ".section .fixup,\"ax\"                 \n"     \
  20                "4:     l.j     3b                      \n"     \
  21                "        l.addi %1, r0, %3              \n"     \
  22                ".previous                              \n"     \
  23                ".section __ex_table,\"a\"              \n"     \
  24                ".word  1b,4b,2b,4b                     \n"     \
  25                ".previous                              \n"     \
  26                : "=&r" (oldval), "=&r" (ret), "+m" (*uaddr)    \
  27                : "i" (-EFAULT), "r" (oparg)                    \
  28                : "cc", "memory"                                \
  29                );                                              \
  30})
  31
  32static inline int
  33futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
  34{
  35        int op = (encoded_op >> 28) & 7;
  36        int cmp = (encoded_op >> 24) & 15;
  37        int oparg = (encoded_op << 8) >> 20;
  38        int cmparg = (encoded_op << 20) >> 20;
  39        int oldval = 0, ret;
  40
  41        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  42                oparg = 1 << oparg;
  43
  44        if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
  45                return -EFAULT;
  46
  47        pagefault_disable();
  48
  49        switch (op) {
  50        case FUTEX_OP_SET:
  51                __futex_atomic_op("l.or %1,%4,%4", ret, oldval, uaddr, oparg);
  52                break;
  53        case FUTEX_OP_ADD:
  54                __futex_atomic_op("l.add %1,%0,%4", ret, oldval, uaddr, oparg);
  55                break;
  56        case FUTEX_OP_OR:
  57                __futex_atomic_op("l.or %1,%0,%4", ret, oldval, uaddr, oparg);
  58                break;
  59        case FUTEX_OP_ANDN:
  60                __futex_atomic_op("l.and %1,%0,%4", ret, oldval, uaddr, ~oparg);
  61                break;
  62        case FUTEX_OP_XOR:
  63                __futex_atomic_op("l.xor %1,%0,%4", ret, oldval, uaddr, oparg);
  64                break;
  65        default:
  66                ret = -ENOSYS;
  67        }
  68
  69        pagefault_enable();
  70
  71        if (!ret) {
  72                switch (cmp) {
  73                case FUTEX_OP_CMP_EQ:
  74                        ret = (oldval == cmparg);
  75                        break;
  76                case FUTEX_OP_CMP_NE:
  77                        ret = (oldval != cmparg);
  78                        break;
  79                case FUTEX_OP_CMP_LT:
  80                        ret = (oldval < cmparg);
  81                        break;
  82                case FUTEX_OP_CMP_GE:
  83                        ret = (oldval >= cmparg);
  84                        break;
  85                case FUTEX_OP_CMP_LE:
  86                        ret = (oldval <= cmparg);
  87                        break;
  88                case FUTEX_OP_CMP_GT:
  89                        ret = (oldval > cmparg);
  90                        break;
  91                default:
  92                        ret = -ENOSYS;
  93                }
  94        }
  95        return ret;
  96}
  97
  98static inline int
  99futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 100                              u32 oldval, u32 newval)
 101{
 102        int ret = 0;
 103        u32 prev;
 104
 105        if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 106                return -EFAULT;
 107
 108        __asm__ __volatile__ (                          \
 109                "1:     l.lwa   %1, %2          \n"     \
 110                "       l.sfeq  %1, %3          \n"     \
 111                "       l.bnf   3f              \n"     \
 112                "        l.nop                  \n"     \
 113                "2:     l.swa   %2, %4          \n"     \
 114                "       l.bnf   1b              \n"     \
 115                "        l.nop                  \n"     \
 116                "3:                             \n"     \
 117                ".section .fixup,\"ax\"         \n"     \
 118                "4:     l.j     3b              \n"     \
 119                "        l.addi %0, r0, %5      \n"     \
 120                ".previous                      \n"     \
 121                ".section __ex_table,\"a\"      \n"     \
 122                ".word  1b,4b,2b,4b             \n"     \
 123                ".previous                      \n"     \
 124                : "+r" (ret), "=&r" (prev), "+m" (*uaddr) \
 125                : "r" (oldval), "r" (newval), "i" (-EFAULT) \
 126                : "cc", "memory"                        \
 127                );
 128
 129        *uval = prev;
 130        return ret;
 131}
 132
 133#endif /* __KERNEL__ */
 134
 135#endif /* __ASM_OPENRISC_FUTEX_H */
 136