futex.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * Atomic futex routines
  3. *
  4. * Based on the PowerPC implementataion
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * Copyright (C) 2013 TangoTec Ltd.
  11. *
  12. * Baruch Siach <baruch@tkos.co.il>
  13. */
  14. #ifndef _ASM_XTENSA_FUTEX_H
  15. #define _ASM_XTENSA_FUTEX_H
  16. #ifdef __KERNEL__
  17. #include <linux/futex.h>
  18. #include <linux/uaccess.h>
  19. #include <linux/errno.h>
  20. #define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
  21. __asm__ __volatile( \
  22. "1: l32i %0, %2, 0\n" \
  23. insn "\n" \
  24. " wsr %0, scompare1\n" \
  25. "2: s32c1i %1, %2, 0\n" \
  26. " bne %1, %0, 1b\n" \
  27. " movi %1, 0\n" \
  28. "3:\n" \
  29. " .section .fixup,\"ax\"\n" \
  30. " .align 4\n" \
  31. "4: .long 3b\n" \
  32. "5: l32r %0, 4b\n" \
  33. " movi %1, %3\n" \
  34. " jx %0\n" \
  35. " .previous\n" \
  36. " .section __ex_table,\"a\"\n" \
  37. " .long 1b,5b,2b,5b\n" \
  38. " .previous\n" \
  39. : "=&r" (oldval), "=&r" (ret) \
  40. : "r" (uaddr), "I" (-EFAULT), "r" (oparg) \
  41. : "memory")
  42. static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
  43. {
  44. int op = (encoded_op >> 28) & 7;
  45. int cmp = (encoded_op >> 24) & 15;
  46. int oparg = (encoded_op << 8) >> 20;
  47. int cmparg = (encoded_op << 20) >> 20;
  48. int oldval = 0, ret;
  49. if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
  50. oparg = 1 << oparg;
  51. if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
  52. return -EFAULT;
  53. #if !XCHAL_HAVE_S32C1I
  54. return -ENOSYS;
  55. #endif
  56. pagefault_disable();
  57. switch (op) {
  58. case FUTEX_OP_SET:
  59. __futex_atomic_op("mov %1, %4", ret, oldval, uaddr, oparg);
  60. break;
  61. case FUTEX_OP_ADD:
  62. __futex_atomic_op("add %1, %0, %4", ret, oldval, uaddr,
  63. oparg);
  64. break;
  65. case FUTEX_OP_OR:
  66. __futex_atomic_op("or %1, %0, %4", ret, oldval, uaddr,
  67. oparg);
  68. break;
  69. case FUTEX_OP_ANDN:
  70. __futex_atomic_op("and %1, %0, %4", ret, oldval, uaddr,
  71. ~oparg);
  72. break;
  73. case FUTEX_OP_XOR:
  74. __futex_atomic_op("xor %1, %0, %4", ret, oldval, uaddr,
  75. oparg);
  76. break;
  77. default:
  78. ret = -ENOSYS;
  79. }
  80. pagefault_enable();
  81. if (ret)
  82. return ret;
  83. switch (cmp) {
  84. case FUTEX_OP_CMP_EQ: return (oldval == cmparg);
  85. case FUTEX_OP_CMP_NE: return (oldval != cmparg);
  86. case FUTEX_OP_CMP_LT: return (oldval < cmparg);
  87. case FUTEX_OP_CMP_GE: return (oldval >= cmparg);
  88. case FUTEX_OP_CMP_LE: return (oldval <= cmparg);
  89. case FUTEX_OP_CMP_GT: return (oldval > cmparg);
  90. }
  91. return -ENOSYS;
  92. }
  93. static inline int
  94. futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  95. u32 oldval, u32 newval)
  96. {
  97. int ret = 0;
  98. u32 prev;
  99. if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
  100. return -EFAULT;
  101. #if !XCHAL_HAVE_S32C1I
  102. return -ENOSYS;
  103. #endif
  104. __asm__ __volatile__ (
  105. " # futex_atomic_cmpxchg_inatomic\n"
  106. "1: l32i %1, %3, 0\n"
  107. " mov %0, %5\n"
  108. " wsr %1, scompare1\n"
  109. "2: s32c1i %0, %3, 0\n"
  110. "3:\n"
  111. " .section .fixup,\"ax\"\n"
  112. " .align 4\n"
  113. "4: .long 3b\n"
  114. "5: l32r %1, 4b\n"
  115. " movi %0, %6\n"
  116. " jx %1\n"
  117. " .previous\n"
  118. " .section __ex_table,\"a\"\n"
  119. " .long 1b,5b,2b,5b\n"
  120. " .previous\n"
  121. : "+r" (ret), "=&r" (prev), "+m" (*uaddr)
  122. : "r" (uaddr), "r" (oldval), "r" (newval), "I" (-EFAULT)
  123. : "memory");
  124. *uval = prev;
  125. return ret;
  126. }
  127. #endif /* __KERNEL__ */
  128. #endif /* _ASM_XTENSA_FUTEX_H */