core, lib, modules: restructured source code tree
[sip-router] / src / core / atomic / atomic_alpha.h
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 /** 
18  * @file
19  * @brief Atomic operations and memory barriers (alpha specific)
20  *
21  * Atomic operations and memory barriers (alpha specific)
22  * \warning atomic ops do not include memory barriers, see atomic_ops.h
23  * for more details.
24  * 
25  * Config defines:
26  * - NOSMP 
27  * - __CPU_alpha
28  * @ingroup atomic
29  */
30
31
32 #ifndef _atomic_alpha_h
33 #define _atomic_alpha_h
34
35 #define HAVE_ASM_INLINE_ATOMIC_OPS
36 #define HAVE_ASM_INLINE_MEMBAR
37
38 #warning alpha atomic code was not tested, please report problems to \
39                 serdev@iptel.org or andrei@iptel.org
40
41 #ifdef NOSMP
42 #define membar() asm volatile ("" : : : "memory") /* gcc do not cache barrier*/
43 #define membar_read()  membar()
44 #define membar_write() membar()
45 #define membar_depends()  do {} while(0) /* really empty, not even a cc bar. */
46 /* lock barriers: empty, not needed for NOSMP; the lock/unlock should already
47  * contain gcc barriers*/
48 #define membar_enter_lock() do {} while(0)
49 #define membar_leave_lock() do {} while(0)
50 /* membars after or before atomic_ops or atomic_setget -> use these or
51  *  mb_<atomic_op_name>() if you need a memory barrier in one of these
52  *  situations (on some archs where the atomic operations imply memory
53  *   barriers is better to use atomic_op_x(); membar_atomic_op() then
54  *    atomic_op_x(); membar()) */
55 #define membar_atomic_op()                              membar()
56 #define membar_atomic_setget()                  membar()
57 #define membar_write_atomic_op()                membar_write()
58 #define membar_write_atomic_setget()    membar_write()
59 #define membar_read_atomic_op()                 membar_read()
60 #define membar_read_atomic_setget()             membar_read()
61
62 #else
63
64 #define membar()                asm volatile ("    mb \n\t" : : : "memory" ) 
65 #define membar_read()   membar()
66 #define membar_write()  asm volatile ("    wmb \n\t" : : : "memory" )
67 #define membar_depends()        asm volatile ("mb \n\t" : : : "memory" )
68 #define membar_enter_lock() asm volatile("mb \n\t" : : : "memory")
69 #define membar_leave_lock() asm volatile("mb \n\t" : : : "memory")
70
71 /* membars after or before atomic_ops or atomic_setget -> use these or
72  *  mb_<atomic_op_name>() if you need a memory barrier in one of these
73  *  situations (on some archs where the atomic operations imply memory
74  *   barriers is better to use atomic_op_x(); membar_atomic_op() then
75  *    atomic_op_x(); membar()) */
76 #define membar_atomic_op()                              membar()
77 #define membar_atomic_setget()                  membar()
78 #define membar_write_atomic_op()                membar_write()
79 #define membar_write_atomic_setget()    membar_write()
80 #define membar_read_atomic_op()                 membar_read()
81 #define membar_read_atomic_setget()             membar_read()
82 #endif /* NOSMP */
83
84
85
86 /* main asm block 
87  * if store failes, jump _forward_ (optimization, because back jumps are
88  *  always predicted to happen on alpha )*/
89 #define ATOMIC_ASM_OP00_int(op) \
90                         "1:   ldl_l %0, %2 \n\t" \
91                         "     " op "\n\t" \
92                         "     stl_c %0, %2 \n\t" \
93                         "     beq %0, 2f \n\t" \
94                         ".subsection 2 \n\t" \
95                         "2:   br 1b \n\t" \
96                         ".previous \n\t"
97
98 /* as above, but output in %1 instead of %0 (%0 is not clobbered) */
99 #define ATOMIC_ASM_OP01_int(op) \
100                         "1:   ldl_l %0, %3 \n\t" \
101                         "     " op "\n\t" \
102                         "     stl_c %1, %3 \n\t" \
103                         "     beq %1, 2f \n\t" \
104                         ".subsection 2 \n\t" \
105                         "2:   br 1b \n\t" \
106                         ".previous \n\t"
107
108 #define ATOMIC_ASM_OP00_long(op) \
109                         "1:   ldq_l %0, %2 \n\t" \
110                         "     " op "\n\t" \
111                         "     stq_c %0, %2 \n\t" \
112                         "     beq %0, 2f \n\t" \
113                         ".subsection 2 \n\t" \
114                         "2:   br 1b \n\t" \
115                         ".previous \n\t"
116
117 /* as above, but output in %1 instead of %0 (%0 is not clobbered) */
118 #define ATOMIC_ASM_OP01_long(op) \
119                         "1:   ldq_l %0, %3 \n\t" \
120                         "     " op "\n\t" \
121                         "     stq_c %1, %3 \n\t" \
122                         "     beq %1, 2f \n\t" \
123                         ".subsection 2 \n\t" \
124                         "2:   br 1b \n\t" \
125                         ".previous \n\t"
126
127
128
129 /* input in %0, output in %0 */
130 #define ATOMIC_FUNC_DECL0_0(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
131         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
132         { \
133                 P_TYPE ret; \
134                 asm volatile( \
135                         ATOMIC_ASM_OP00_##P_TYPE(OP) : "=&r"(ret), "=m"(*var) : "m"(*var) \
136                         ); \
137                 return RET_EXPR; \
138         }
139
140
141 #if defined __GNUC__ &&  __GNUC__ < 3 && __GNUC_MINOR__ < 9
142 #define ATOMIC_FUNC_DECL01_1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
143         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
144                                                                                                                 P_TYPE v ) \
145         { \
146                 P_TYPE ret; \
147                 asm volatile( \
148                         ATOMIC_ASM_OP01_##P_TYPE(OP) \
149                         : "=&r"(ret), "=r"(v), "=m"(*var)  : "m"(*var), "1"(v) \
150                         ); \
151                 return RET_EXPR; \
152         }
153 #else
154 /* input in %0, and %1 (param), output in %1,  %0 goes in ret */
155 #define ATOMIC_FUNC_DECL01_1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
156         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
157                                                                                                                 P_TYPE v ) \
158         { \
159                 P_TYPE ret; \
160                 asm volatile( \
161                         ATOMIC_ASM_OP01_##P_TYPE(OP) \
162                         : "=&r"(ret), "+r"(v), "=m"(*var)  : "m"(*var) \
163                         ); \
164                 return RET_EXPR; \
165         }
166 #endif /* gcc && gcc version < 2.9 */
167
168 /* input in %0, output in %1, %0 goes in ret */
169 #define ATOMIC_FUNC_DECL0_1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
170         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
171         { \
172                 P_TYPE ret, tmp; \
173                 asm volatile( \
174                         ATOMIC_ASM_OP01_##P_TYPE(OP) \
175                         : "=&r"(ret), "=&r"(tmp), "=m"(*var)  : "m"(*var) \
176                         ); \
177                 return RET_EXPR; \
178         }
179
180
181 /* input in %0 and %3 (param), output in %0 */
182 #define ATOMIC_FUNC_DECL03_0(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
183         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
184                                                                                                                 P_TYPE v) \
185         { \
186                 P_TYPE ret; \
187                 asm volatile( \
188                         ATOMIC_ASM_OP00_##P_TYPE(OP) \
189                         : "=&r"(ret), "=m"(*var)  : "m"(*var), "r"(v) \
190                         ); \
191                 return RET_EXPR; \
192         }
193
194 /* input in %0 and %3 (param), output in %0 */
195 /* cmpxchg var in %1, old in %0, new_v in %
196  * makes the xchg if old==*var
197  * returns initial *var (so if ret==old => new_v was written into var)*/
198 #define ATOMIC_CMPXCHG_DECL(NAME,  P_TYPE) \
199         inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
200                                                                                                                 P_TYPE old, \
201                                                                                                                 P_TYPE new_v) \
202         { \
203                 P_TYPE ret; \
204                 P_TYPE tmp; \
205                 asm volatile( \
206                         ATOMIC_ASM_OP01_##P_TYPE("subq  %0, %5, %2 \n\t bne %2, 3f")\
207                         "3:    \n\t" \
208                         : "=&r"(ret), "=&r"(new_v), "=r"(tmp), "=m"(*var)  :\
209                                 "m"(*var), "r"(old), "1"(new_v) :"cc" \
210                         ); \
211                 return ret; \
212         }
213
214
215 ATOMIC_FUNC_DECL0_0(inc, "addl %0, 1, %0", int, void, /* no return */ )
216 ATOMIC_FUNC_DECL0_0(dec, "subl %0, 1, %0", int, void, /* no return */ )
217 ATOMIC_FUNC_DECL03_0(and, "and %0, %3, %0", int, void, /* no return */ )
218 ATOMIC_FUNC_DECL03_0(or,  "bis %0, %3, %0", int, void, /* no return */ )
219 ATOMIC_FUNC_DECL0_1(inc_and_test, "addl %0, 1, %1", int, int, (ret+1)==0 )
220 ATOMIC_FUNC_DECL0_1(dec_and_test, "subl %0, 1, %1", int, int, (ret-1)==0 )
221 ATOMIC_FUNC_DECL01_1(get_and_set, "" /* nothing needed */, int, int, ret )
222 ATOMIC_CMPXCHG_DECL(cmpxchg, int )
223 ATOMIC_FUNC_DECL01_1(add, "addl %1, %0, %1", int, int, ret+v)
224
225 ATOMIC_FUNC_DECL0_0(inc, "addq %0, 1, %0", long, void, /* no return */ )
226 ATOMIC_FUNC_DECL0_0(dec, "subq %0, 1, %0", long, void, /* no return */ )
227 ATOMIC_FUNC_DECL03_0(and, "and %0, %3, %0", long, void, /* no return */ )
228 ATOMIC_FUNC_DECL03_0(or,  "bis %0, %3, %0", long, void, /* no return */ )
229 ATOMIC_FUNC_DECL0_1(inc_and_test, "addq %0, 1, %1", long, long, (ret+1)==0 )
230 ATOMIC_FUNC_DECL0_1(dec_and_test, "subq %0, 1, %1", long, long, (ret-1)==0 )
231 ATOMIC_FUNC_DECL01_1(get_and_set, "" /* nothing needed */, long, long, ret )
232 ATOMIC_CMPXCHG_DECL(cmpxchg, long )
233 ATOMIC_FUNC_DECL01_1(add, "addq %1, %0, %1", long, long, ret+v)
234
235
236 #define atomic_inc(var) atomic_inc_int(&(var)->val)
237 #define atomic_dec(var) atomic_dec_int(&(var)->val)
238 #define atomic_and(var, mask) atomic_and_int(&(var)->val, (mask))
239 #define atomic_or(var, mask)  atomic_or_int(&(var)->val, (mask))
240 #define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
241 #define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
242 #define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
243 #define atomic_cmpxchg(var, old, new_v) \
244                 atomic_cmpxchg_int(&(var)->val, old, new_v)
245 #define atomic_add(var, v) atomic_add_int(&(var)->val, (v))
246
247
248 /* with integrated membar */
249
250 #define mb_atomic_set_int(v, i) \
251         do{ \
252                 membar(); \
253                 atomic_set_int(v, i); \
254         }while(0)
255
256
257
258 inline static int mb_atomic_get_int(volatile int* v)
259 {
260         membar();
261         return atomic_get_int(v);
262 }
263
264
265 #define mb_atomic_inc_int(v) \
266         do{ \
267                 membar(); \
268                 atomic_inc_int(v); \
269         }while(0)
270
271 #define mb_atomic_dec_int(v) \
272         do{ \
273                 membar(); \
274                 atomic_dec_int(v); \
275         }while(0)
276
277 #define mb_atomic_or_int(v, m) \
278         do{ \
279                 membar(); \
280                 atomic_or_int(v, m); \
281         }while(0)
282
283 #define mb_atomic_and_int(v, m) \
284         do{ \
285                 membar(); \
286                 atomic_and_int(v, m); \
287         }while(0)
288
289 inline static int mb_atomic_inc_and_test_int(volatile int* v)
290 {
291         membar();
292         return atomic_inc_and_test_int(v);
293 }
294
295 inline static int mb_atomic_dec_and_test_int(volatile int* v)
296 {
297         membar();
298         return atomic_dec_and_test_int(v);
299 }
300
301
302 inline static int mb_atomic_get_and_set_int(volatile int* v, int i)
303 {
304         membar();
305         return atomic_get_and_set_int(v, i);
306 }
307
308 inline static int mb_atomic_cmpxchg_int(volatile int* v, int o, int n)
309 {
310         membar();
311         return atomic_cmpxchg_int(v, o, n);
312 }
313
314 inline static int mb_atomic_add_int(volatile int* v, int i)
315 {
316         membar();
317         return atomic_add_int(v, i);
318 }
319
320
321
322 #define mb_atomic_set_long(v, i) \
323         do{ \
324                 membar(); \
325                 atomic_set_long(v, i); \
326         }while(0)
327
328
329
330 inline static long mb_atomic_get_long(volatile long* v)
331 {
332         membar();
333         return atomic_get_long(v);
334 }
335
336
337 #define mb_atomic_inc_long(v) \
338         do{ \
339                 membar(); \
340                 atomic_inc_long(v); \
341         }while(0)
342
343
344 #define mb_atomic_dec_long(v) \
345         do{ \
346                 membar(); \
347                 atomic_dec_long(v); \
348         }while(0)
349
350 #define mb_atomic_or_long(v, m) \
351         do{ \
352                 membar(); \
353                 atomic_or_long(v, m); \
354         }while(0)
355
356 #define mb_atomic_and_long(v, m) \
357         do{ \
358                 membar(); \
359                 atomic_and_long(v, m); \
360         }while(0)
361
362 inline static long mb_atomic_inc_and_test_long(volatile long* v)
363 {
364         membar();
365         return atomic_inc_and_test_long(v);
366 }
367
368 inline static long mb_atomic_dec_and_test_long(volatile long* v)
369 {
370         membar();
371         return atomic_dec_and_test_long(v);
372 }
373
374
375 inline static long mb_atomic_get_and_set_long(volatile long* v, long l)
376 {
377         membar();
378         return atomic_get_and_set_long(v, l);
379 }
380
381
382 inline static long mb_atomic_cmpxchg_long(volatile long* v, long o, long n)
383 {
384         membar();
385         return atomic_cmpxchg_long(v, o, n);
386 }
387
388 inline static long mb_atomic_add_long(volatile long* v, long i)
389 {
390         membar();
391         return atomic_add_long(v, i);
392 }
393
394
395 #define mb_atomic_inc(var) mb_atomic_inc_int(&(var)->val)
396 #define mb_atomic_dec(var) mb_atomic_dec_int(&(var)->val)
397 #define mb_atomic_and(var, mask) mb_atomic_and_int(&(var)->val, (mask))
398 #define mb_atomic_or(var, mask)  mb_atomic_or_int(&(var)->val, (mask))
399 #define mb_atomic_dec_and_test(var) mb_atomic_dec_and_test_int(&(var)->val)
400 #define mb_atomic_inc_and_test(var) mb_atomic_inc_and_test_int(&(var)->val)
401 #define mb_atomic_get(var)      mb_atomic_get_int(&(var)->val)
402 #define mb_atomic_set(var, i)   mb_atomic_set_int(&(var)->val, i)
403 #define mb_atomic_get_and_set(var, i) mb_atomic_get_and_set_int(&(var)->val, i)
404 #define mb_atomic_cmpxchg(var, o, n) mb_atomic_cmpxchg_int(&(var)->val, o, n)
405 #define mb_atomic_add(var, i) mb_atomic_add_int(&(var)->val, i)
406
407
408 #endif