linux/arch/tile/include/asm/futex.h
<<
>>
Prefs
   1/*
   2 * Copyright 2010 Tilera Corporation. All Rights Reserved.
   3 *
   4 *   This program is free software; you can redistribute it and/or
   5 *   modify it under the terms of the GNU General Public License
   6 *   as published by the Free Software Foundation, version 2.
   7 *
   8 *   This program is distributed in the hope that it will be useful, but
   9 *   WITHOUT ANY WARRANTY; without even the implied warranty of
  10 *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11 *   NON INFRINGEMENT.  See the GNU General Public License for
  12 *   more details.
  13 *
  14 * These routines make two important assumptions:
  15 *
  16 * 1. atomic_t is really an int and can be freely cast back and forth
  17 *    (validated in __init_atomic_per_cpu).
  18 *
  19 * 2. userspace uses sys_cmpxchg() for all atomic operations, thus using
  20 *    the same locking convention that all the kernel atomic routines use.
  21 */
  22
  23#ifndef _ASM_TILE_FUTEX_H
  24#define _ASM_TILE_FUTEX_H
  25
  26#ifndef __ASSEMBLY__
  27
  28#include <linux/futex.h>
  29#include <linux/uaccess.h>
  30#include <linux/errno.h>
  31
  32extern struct __get_user futex_set(u32 __user *v, int i);
  33extern struct __get_user futex_add(u32 __user *v, int n);
  34extern struct __get_user futex_or(u32 __user *v, int n);
  35extern struct __get_user futex_andn(u32 __user *v, int n);
  36extern struct __get_user futex_cmpxchg(u32 __user *v, int o, int n);
  37
  38#ifndef __tilegx__
  39extern struct __get_user futex_xor(u32 __user *v, int n);
  40#else
  41static inline struct __get_user futex_xor(u32 __user *uaddr, int n)
  42{
  43        struct __get_user asm_ret = __get_user_4(uaddr);
  44        if (!asm_ret.err) {
  45                int oldval, newval;
  46                do {
  47                        oldval = asm_ret.val;
  48                        newval = oldval ^ n;
  49                        asm_ret = futex_cmpxchg(uaddr, oldval, newval);
  50                } while (asm_ret.err == 0 && oldval != asm_ret.val);
  51        }
  52        return asm_ret;
  53}
  54#endif
  55
  56static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
  57{
  58        int op = (encoded_op >> 28) & 7;
  59        int cmp = (encoded_op >> 24) & 15;
  60        int oparg = (encoded_op << 8) >> 20;
  61        int cmparg = (encoded_op << 20) >> 20;
  62        int ret;
  63        struct __get_user asm_ret;
  64
  65        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  66                oparg = 1 << oparg;
  67
  68        if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
  69                return -EFAULT;
  70
  71        pagefault_disable();
  72        switch (op) {
  73        case FUTEX_OP_SET:
  74                asm_ret = futex_set(uaddr, oparg);
  75                break;
  76        case FUTEX_OP_ADD:
  77                asm_ret = futex_add(uaddr, oparg);
  78                break;
  79        case FUTEX_OP_OR:
  80                asm_ret = futex_or(uaddr, oparg);
  81                break;
  82        case FUTEX_OP_ANDN:
  83                asm_ret = futex_andn(uaddr, oparg);
  84                break;
  85        case FUTEX_OP_XOR:
  86                asm_ret = futex_xor(uaddr, oparg);
  87                break;
  88        default:
  89                asm_ret.err = -ENOSYS;
  90        }
  91        pagefault_enable();
  92
  93        ret = asm_ret.err;
  94
  95        if (!ret) {
  96                switch (cmp) {
  97                case FUTEX_OP_CMP_EQ:
  98                        ret = (asm_ret.val == cmparg);
  99                        break;
 100                case FUTEX_OP_CMP_NE:
 101                        ret = (asm_ret.val != cmparg);
 102                        break;
 103                case FUTEX_OP_CMP_LT:
 104                        ret = (asm_ret.val < cmparg);
 105                        break;
 106                case FUTEX_OP_CMP_GE:
 107                        ret = (asm_ret.val >= cmparg);
 108                        break;
 109                case FUTEX_OP_CMP_LE:
 110                        ret = (asm_ret.val <= cmparg);
 111                        break;
 112                case FUTEX_OP_CMP_GT:
 113                        ret = (asm_ret.val > cmparg);
 114                        break;
 115                default:
 116                        ret = -ENOSYS;
 117                }
 118        }
 119        return ret;
 120}
 121
 122static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
 123                                                u32 oldval, u32 newval)
 124{
 125        struct __get_user asm_ret;
 126
 127        if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 128                return -EFAULT;
 129
 130        asm_ret = futex_cmpxchg(uaddr, oldval, newval);
 131        *uval = asm_ret.val;
 132        return asm_ret.err;
 133}
 134
 135#ifndef __tilegx__
 136/* Return failure from the atomic wrappers. */
 137struct __get_user __atomic_bad_address(int __user *addr);
 138#endif
 139
 140#endif /* !__ASSEMBLY__ */
 141
 142#endif /* _ASM_TILE_FUTEX_H */
 143