futex.h 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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 arch_futex_atomic_op_inuser(int op, int oparg, int *oval,
  43. u32 __user *uaddr)
  44. {
  45. int oldval = 0, ret;
  46. #if !XCHAL_HAVE_S32C1I
  47. return -ENOSYS;
  48. #endif
  49. pagefault_disable();
  50. switch (op) {
  51. case FUTEX_OP_SET:
  52. __futex_atomic_op("mov %1, %4", ret, oldval, uaddr, oparg);
  53. break;
  54. case FUTEX_OP_ADD:
  55. __futex_atomic_op("add %1, %0, %4", ret, oldval, uaddr,
  56. oparg);
  57. break;
  58. case FUTEX_OP_OR:
  59. __futex_atomic_op("or %1, %0, %4", ret, oldval, uaddr,
  60. oparg);
  61. break;
  62. case FUTEX_OP_ANDN:
  63. __futex_atomic_op("and %1, %0, %4", ret, oldval, uaddr,
  64. ~oparg);
  65. break;
  66. case FUTEX_OP_XOR:
  67. __futex_atomic_op("xor %1, %0, %4", ret, oldval, uaddr,
  68. oparg);
  69. break;
  70. default:
  71. ret = -ENOSYS;
  72. }
  73. pagefault_enable();
  74. if (!ret)
  75. *oval = oldval;
  76. return ret;
  77. }
  78. static inline int
  79. futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
  80. u32 oldval, u32 newval)
  81. {
  82. int ret = 0;
  83. if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
  84. return -EFAULT;
  85. #if !XCHAL_HAVE_S32C1I
  86. return -ENOSYS;
  87. #endif
  88. __asm__ __volatile__ (
  89. " # futex_atomic_cmpxchg_inatomic\n"
  90. " wsr %5, scompare1\n"
  91. "1: s32c1i %1, %4, 0\n"
  92. " s32i %1, %6, 0\n"
  93. "2:\n"
  94. " .section .fixup,\"ax\"\n"
  95. " .align 4\n"
  96. "3: .long 2b\n"
  97. "4: l32r %1, 3b\n"
  98. " movi %0, %7\n"
  99. " jx %1\n"
  100. " .previous\n"
  101. " .section __ex_table,\"a\"\n"
  102. " .long 1b,4b\n"
  103. " .previous\n"
  104. : "+r" (ret), "+r" (newval), "+m" (*uaddr), "+m" (*uval)
  105. : "r" (uaddr), "r" (oldval), "r" (uval), "I" (-EFAULT)
  106. : "memory");
  107. return ret;
  108. }
  109. #endif /* __KERNEL__ */
  110. #endif /* _ASM_XTENSA_FUTEX_H */