atomic_mips2.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /*
  2. * Copyright (C) 2006 iptelorg GmbH
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. /**
  17. * @file
  18. * @brief Atomic operations and memory barriers (MIPS isa 2 and MIPS64 specific)
  19. *
  20. * Atomic operations and memory barriers (MIPS isa 2 and MIPS64 specific)
  21. * \warning atomic ops do not include memory barriers, see atomic_ops.h for
  22. * more details.
  23. * \warning not tested on MIPS64 (not even a compile test)
  24. *
  25. * Config defines:
  26. * - NOSMP (in NOSMP mode it will also work on mips isa 1 CPUs that support
  27. * LL and SC, see MIPS_HAS_LLSC in atomic_ops.h)
  28. * - __CPU_MIPS64 (mips64 arch., in 64 bit mode: long and void* are 64 bits)
  29. * - __CPU_MIPS2 or __CPU_MIPS && MIPS_HAS_LLSC && NOSMP (if __CPU_MIPS64 is not defined)
  30. * @ingroup atomic
  31. */
  32. /*
  33. * History:
  34. * --------
  35. * 2006-03-08 created by andrei
  36. * 2007-05-10 added atomic_add & atomic_cmpxchg (andrei)
  37. * 2007-05-29 added membar_depends(), membar_*_atomic_op and
  38. * membar_*_atomic_setget (andrei)
  39. */
  40. #ifndef _atomic_mips2_h
  41. #define _atomic_mips2_h
  42. #define HAVE_ASM_INLINE_ATOMIC_OPS
  43. #define HAVE_ASM_INLINE_MEMBAR
  44. #ifdef __CPU_mips64
  45. #warning mips64 atomic code was not tested, please report problems to \
  46. [email protected] or [email protected]
  47. #endif
  48. #ifdef NOSMP
  49. #define membar() asm volatile ("" : : : "memory") /* gcc do not cache barrier*/
  50. #define membar_read() membar()
  51. #define membar_write() membar()
  52. #define membar_depends() do {} while(0) /* really empty, not even a cc bar. */
  53. /* lock barriers: empty, not needed for NOSMP; the lock/unlock should already
  54. * contain gcc barriers*/
  55. #define membar_enter_lock() do {} while(0)
  56. #define membar_leave_lock() do {} while(0)
  57. /* membars after or before atomic_ops or atomic_setget -> use these or
  58. * mb_<atomic_op_name>() if you need a memory barrier in one of these
  59. * situations (on some archs where the atomic operations imply memory
  60. * barriers is better to use atomic_op_x(); membar_atomic_op() then
  61. * atomic_op_x(); membar()) */
  62. #define membar_atomic_op() membar()
  63. #define membar_atomic_setget() membar()
  64. #define membar_write_atomic_op() membar_write()
  65. #define membar_write_atomic_setget() membar_write()
  66. #define membar_read_atomic_op() membar_read()
  67. #define membar_read_atomic_setget() membar_read()
  68. #else
  69. #define membar() \
  70. asm volatile( \
  71. ".set push \n\t" \
  72. ".set noreorder \n\t" \
  73. ".set mips2 \n\t" \
  74. " sync\n\t" \
  75. ".set pop \n\t" \
  76. : : : "memory" \
  77. )
  78. #define membar_read() membar()
  79. #define membar_write() membar()
  80. #define membar_depends() do {} while(0) /* really empty, not even a cc bar. */
  81. #define membar_enter_lock() membar()
  82. #define membar_leave_lock() membar()
  83. /* membars after or before atomic_ops or atomic_setget -> use these or
  84. * mb_<atomic_op_name>() if you need a memory barrier in one of these
  85. * situations (on some archs where the atomic operations imply memory
  86. * barriers is better to use atomic_op_x(); membar_atomic_op() then
  87. * atomic_op_x(); membar()) */
  88. #define membar_atomic_op() membar()
  89. #define membar_atomic_setget() membar()
  90. #define membar_write_atomic_op() membar_write()
  91. #define membar_write_atomic_setget() membar_write()
  92. #define membar_read_atomic_op() membar_read()
  93. #define membar_read_atomic_setget() membar_read()
  94. #endif /* NOSMP */
  95. /* main asm block */
  96. #define ATOMIC_ASM_OP_int(op) \
  97. ".set push \n\t" \
  98. ".set noreorder \n\t" \
  99. ".set mips2 \n\t" \
  100. "1: ll %1, %0 \n\t" \
  101. " " op "\n\t" \
  102. " sc %2, %0 \n\t" \
  103. " beqz %2, 1b \n\t" \
  104. " nop \n\t" /* delay slot */ \
  105. ".set pop \n\t"
  106. #ifdef __CPU_mips64
  107. #define ATOMIC_ASM_OP_long(op) \
  108. ".set push \n\t" \
  109. ".set noreorder \n\t" \
  110. "1: lld %1, %0 \n\t" \
  111. " " op "\n\t" \
  112. " scd %2, %0 \n\t" \
  113. " beqz %2, 1b \n\t" \
  114. " nop \n\t" /* delay slot */ \
  115. ".set pop \n\t"
  116. #else /* ! __CPU_mips64 => __CPU_mips2 or __CPU_mips & MIPS_HAS_LLSC */
  117. #define ATOMIC_ASM_OP_long(op) ATOMIC_ASM_OP_int(op)
  118. #endif
  119. #define ATOMIC_FUNC_DECL(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
  120. inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
  121. { \
  122. P_TYPE ret, tmp; \
  123. asm volatile( \
  124. ATOMIC_ASM_OP_##P_TYPE(OP) \
  125. : "=m"(*var), "=&r"(ret), "=&r"(tmp) \
  126. : "m"(*var) \
  127. \
  128. ); \
  129. return RET_EXPR; \
  130. }
  131. /* same as above, but with CT in %3 */
  132. #define ATOMIC_FUNC_DECL_CT(NAME, OP, CT, P_TYPE, RET_TYPE, RET_EXPR) \
  133. inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
  134. { \
  135. P_TYPE ret, tmp; \
  136. asm volatile( \
  137. ATOMIC_ASM_OP_##P_TYPE(OP) \
  138. : "=m"(*var), "=&r"(ret), "=&r"(tmp) \
  139. : "r"((CT)), "m"(*var) \
  140. \
  141. ); \
  142. return RET_EXPR; \
  143. }
  144. /* takes an extra param, i which goes in %3 */
  145. #define ATOMIC_FUNC_DECL1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
  146. inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
  147. P_TYPE i) \
  148. { \
  149. P_TYPE ret, tmp; \
  150. asm volatile( \
  151. ATOMIC_ASM_OP_##P_TYPE(OP) \
  152. : "=m"(*var), "=&r"(ret), "=&r"(tmp) \
  153. : "r"((i)), "m"(*var) \
  154. \
  155. ); \
  156. return RET_EXPR; \
  157. }
  158. /* takes an extra param, like above, but i goes in %2 */
  159. #define ATOMIC_FUNC_DECL2(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
  160. inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
  161. P_TYPE i) \
  162. { \
  163. P_TYPE ret; \
  164. asm volatile( \
  165. ATOMIC_ASM_OP_##P_TYPE(OP) \
  166. : "=m"(*var), "=&r"(ret), "+&r"(i) \
  167. : "m"(*var) \
  168. \
  169. ); \
  170. return RET_EXPR; \
  171. }
  172. /* %0=var, %1=*var, %2=new, %3=old :
  173. * ret=*var; if *var==old then *var=new; return ret
  174. * => if succesfull (changed var to new) ret==old */
  175. #define ATOMIC_CMPXCHG_DECL(NAME, P_TYPE) \
  176. inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
  177. P_TYPE old, \
  178. P_TYPE new_v) \
  179. { \
  180. asm volatile( \
  181. ATOMIC_ASM_OP_##P_TYPE("bne %1, %3, 2f \n\t nop") \
  182. "2: \n\t" \
  183. : "=m"(*var), "=&r"(old), "=r"(new_v) \
  184. : "r"(old), "m"(*var), "2"(new_v) \
  185. \
  186. ); \
  187. return old; \
  188. }
  189. ATOMIC_FUNC_DECL(inc, "addiu %2, %1, 1", int, void, /* no return */ )
  190. ATOMIC_FUNC_DECL_CT(dec, "subu %2, %1, %3", 1, int, void, /* no return */ )
  191. ATOMIC_FUNC_DECL1(and, "and %2, %1, %3", int, void, /* no return */ )
  192. ATOMIC_FUNC_DECL1(or, "or %2, %1, %3", int, void, /* no return */ )
  193. ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", int, int, (ret+1)==0 )
  194. ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1, int, int, (ret-1)==0 )
  195. ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, int, int, ret )
  196. ATOMIC_CMPXCHG_DECL(cmpxchg, int)
  197. ATOMIC_FUNC_DECL1(add, "addu %2, %1, %3 \n\t move %1, %2", int, int, ret )
  198. #ifdef __CPU_mips64
  199. ATOMIC_FUNC_DECL(inc, "daddiu %2, %1, 1", long, void, /* no return */ )
  200. ATOMIC_FUNC_DECL_CT(dec, "dsubu %2, %1, %3", 1, long, void, /* no return */ )
  201. ATOMIC_FUNC_DECL1(and, "and %2, %1, %3", long, void, /* no return */ )
  202. ATOMIC_FUNC_DECL1(or, "or %2, %1, %3", long, void, /* no return */ )
  203. ATOMIC_FUNC_DECL(inc_and_test, "daddiu %2, %1, 1", long, long, (ret+1)==0 )
  204. ATOMIC_FUNC_DECL_CT(dec_and_test, "dsubu %2, %1, %3", 1,long, long, (ret-1)==0 )
  205. ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
  206. ATOMIC_CMPXCHG_DECL(cmpxchg, long)
  207. ATOMIC_FUNC_DECL1(add, "daddu %2, %1, %3 \n\t move %1, %2", long, long, ret )
  208. #else /* ! __CPU_mips64 => __CPU_mips2 or __CPU_mips */
  209. ATOMIC_FUNC_DECL(inc, "addiu %2, %1, 1", long, void, /* no return */ )
  210. ATOMIC_FUNC_DECL_CT(dec, "subu %2, %1, %3", 1, long, void, /* no return */ )
  211. ATOMIC_FUNC_DECL1(and, "and %2, %1, %3", long, void, /* no return */ )
  212. ATOMIC_FUNC_DECL1(or, "or %2, %1, %3", long, void, /* no return */ )
  213. ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", long, long, (ret+1)==0 )
  214. ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1,long, long, (ret-1)==0 )
  215. ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
  216. ATOMIC_CMPXCHG_DECL(cmpxchg, long)
  217. ATOMIC_FUNC_DECL1(add, "addu %2, %1, %3 \n\t move %1, %2", long, long, ret )
  218. #endif /* __CPU_mips64 */
  219. #define atomic_inc(var) atomic_inc_int(&(var)->val)
  220. #define atomic_dec(var) atomic_dec_int(&(var)->val)
  221. #define atomic_and(var, mask) atomic_and_int(&(var)->val, (mask))
  222. #define atomic_or(var, mask) atomic_or_int(&(var)->val, (mask))
  223. #define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
  224. #define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
  225. #define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
  226. #define atomic_add(var, i) atomic_add_int(&(var)->val, i)
  227. #define atomic_cmpxchg(var, old, new_v) \
  228. atomic_cmpxchg_int(&(var)->val, old, new_v)
  229. /* with integrated membar */
  230. #define mb_atomic_set_int(v, i) \
  231. do{ \
  232. membar(); \
  233. atomic_set_int(v, i); \
  234. }while(0)
  235. inline static int mb_atomic_get_int(volatile int* v)
  236. {
  237. membar();
  238. return atomic_get_int(v);
  239. }
  240. #define mb_atomic_inc_int(v) \
  241. do{ \
  242. membar(); \
  243. atomic_inc_int(v); \
  244. }while(0)
  245. #define mb_atomic_dec_int(v) \
  246. do{ \
  247. membar(); \
  248. atomic_dec_int(v); \
  249. }while(0)
  250. #define mb_atomic_or_int(v, m) \
  251. do{ \
  252. membar(); \
  253. atomic_or_int(v, m); \
  254. }while(0)
  255. #define mb_atomic_and_int(v, m) \
  256. do{ \
  257. membar(); \
  258. atomic_and_int(v, m); \
  259. }while(0)
  260. inline static int mb_atomic_inc_and_test_int(volatile int* v)
  261. {
  262. membar();
  263. return atomic_inc_and_test_int(v);
  264. }
  265. inline static int mb_atomic_dec_and_test_int(volatile int* v)
  266. {
  267. membar();
  268. return atomic_dec_and_test_int(v);
  269. }
  270. inline static int mb_atomic_get_and_set_int(volatile int* v, int i)
  271. {
  272. membar();
  273. return atomic_get_and_set_int(v, i);
  274. }
  275. inline static int mb_atomic_cmpxchg_int(volatile int* v, int o, int n)
  276. {
  277. membar();
  278. return atomic_cmpxchg_int(v, o, n);
  279. }
  280. inline static int mb_atomic_add_int(volatile int* v, int i)
  281. {
  282. membar();
  283. return atomic_add_int(v, i);
  284. }
  285. #define mb_atomic_set_long(v, i) \
  286. do{ \
  287. membar(); \
  288. atomic_set_long(v, i); \
  289. }while(0)
  290. inline static long mb_atomic_get_long(volatile long* v)
  291. {
  292. membar();
  293. return atomic_get_long(v);
  294. }
  295. #define mb_atomic_inc_long(v) \
  296. do{ \
  297. membar(); \
  298. atomic_inc_long(v); \
  299. }while(0)
  300. #define mb_atomic_dec_long(v) \
  301. do{ \
  302. membar(); \
  303. atomic_dec_long(v); \
  304. }while(0)
  305. #define mb_atomic_or_long(v, m) \
  306. do{ \
  307. membar(); \
  308. atomic_or_long(v, m); \
  309. }while(0)
  310. #define mb_atomic_and_long(v, m) \
  311. do{ \
  312. membar(); \
  313. atomic_and_long(v, m); \
  314. }while(0)
  315. inline static long mb_atomic_inc_and_test_long(volatile long* v)
  316. {
  317. membar();
  318. return atomic_inc_and_test_long(v);
  319. }
  320. inline static long mb_atomic_dec_and_test_long(volatile long* v)
  321. {
  322. membar();
  323. return atomic_dec_and_test_long(v);
  324. }
  325. inline static long mb_atomic_get_and_set_long(volatile long* v, long l)
  326. {
  327. membar();
  328. return atomic_get_and_set_long(v, l);
  329. }
  330. inline static long mb_atomic_cmpxchg_long(volatile long* v, long o, long n)
  331. {
  332. membar();
  333. return atomic_cmpxchg_long(v, o, n);
  334. }
  335. inline static long mb_atomic_add_long(volatile long* v, long i)
  336. {
  337. membar();
  338. return atomic_add_long(v, i);
  339. }
  340. #define mb_atomic_inc(var) mb_atomic_inc_int(&(var)->val)
  341. #define mb_atomic_dec(var) mb_atomic_dec_int(&(var)->val)
  342. #define mb_atomic_and(var, mask) mb_atomic_and_int(&(var)->val, (mask))
  343. #define mb_atomic_or(var, mask) mb_atomic_or_int(&(var)->val, (mask))
  344. #define mb_atomic_dec_and_test(var) mb_atomic_dec_and_test_int(&(var)->val)
  345. #define mb_atomic_inc_and_test(var) mb_atomic_inc_and_test_int(&(var)->val)
  346. #define mb_atomic_get(var) mb_atomic_get_int(&(var)->val)
  347. #define mb_atomic_set(var, i) mb_atomic_set_int(&(var)->val, i)
  348. #define mb_atomic_get_and_set(var, i) mb_atomic_get_and_set_int(&(var)->val, i)
  349. #define mb_atomic_cmpxchg(var, o, n) mb_atomic_cmpxchg_int(&(var)->val, o, n)
  350. #define mb_atomic_add(var, i) mb_atomic_add_int(&(var)->val, i)
  351. #endif