atomic_sparc64.h

Go to the documentation of this file.
00001 /* 
00002  * Copyright (C) 2006 iptelorg GmbH
00003  *
00004  * Permission to use, copy, modify, and distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00032 /* 
00033  * History:
00034  * --------
00035  *  2006-03-28  created by andrei
00036  *  2007-05-08 added atomic_add and atomic_cmpxchg (andrei)
00037  *  2007-05-29  added membar_depends(), membar_*_atomic_op and
00038  *                membar_*_atomic_setget (andrei)
00039  */
00040 
00041 
00042 #ifndef _atomic_sparc64_h
00043 #define _atomic_sparc64_h
00044 
00045 #define HAVE_ASM_INLINE_ATOMIC_OPS
00046 #define HAVE_ASM_INLINE_MEMBAR
00047 
00048 
00049 
00050 /* try to guess if in SPARC64_MODE */
00051 #if ! defined SPARC64_MODE && \
00052         (defined __LP64__ || defined _LP64 || defined __arch64__)
00053 #define SPARC64_MODE
00054 #endif
00055 
00056 
00057 #ifdef NOSMP
00058 #define membar() asm volatile ("" : : : "memory") /* gcc do not cache barrier*/
00059 #define membar_read()  membar()
00060 #define membar_write() membar()
00061 #define membar_depends()  do {} while(0) /* really empty, not even a cc bar. */
00062 /*  memory barriers for lock & unlock where lock & unlock are inline asm
00063  *  functions that use atomic ops (and both of them use at least a store to
00064  *  the lock). membar_enter_lock() is at most a StoreStore|StoreLoad barrier
00065  *   and membar_leave_lock() is at most a LoadStore|StoreStore barries
00066  *  (if the atomic ops on the specific arhitecture imply these barriers
00067  *   => these macros will be empty)
00068  *   Warning: these barriers don't force LoadLoad ordering between code
00069  *    before the lock/membar_enter_lock() and code 
00070  *    after membar_leave_lock()/unlock()
00071  *
00072  *  Usage: lock(); membar_enter_lock(); .... ; membar_leave_lock(); unlock()
00073  */
00074 #define membar_enter_lock() do {} while(0)
00075 #define membar_leave_lock() do {} while(0)
00076 /* membars after or before atomic_ops or atomic_setget -> use these or
00077  *  mb_<atomic_op_name>() if you need a memory barrier in one of these
00078  *  situations (on some archs where the atomic operations imply memory
00079  *   barriers is better to use atomic_op_x(); membar_atomic_op() then
00080  *    atomic_op_x(); membar()) */
00081 #define membar_atomic_op()                              membar()
00082 #define membar_atomic_setget()                  membar()
00083 #define membar_write_atomic_op()                membar_write()
00084 #define membar_write_atomic_setget()    membar_write()
00085 #define membar_read_atomic_op()                 membar_read()
00086 #define membar_read_atomic_setget()             membar_read()
00087 #else /* SMP */
00088 #define membar() \
00089         asm volatile ( \
00090                         "membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad \n\t" \
00091                         : : : "memory")
00092 
00093 #define membar_read() asm volatile ("membar #LoadLoad \n\t" : : : "memory")
00094 #define membar_write() asm volatile ("membar #StoreStore \n\t" : : : "memory")
00095 #define membar_depends()  do {} while(0) /* really empty, not even a cc bar. */
00096 #define membar_enter_lock() \
00097         asm volatile ("membar #StoreStore | #StoreLoad \n\t" : : : "memory");
00098 #define membar_leave_lock() \
00099         asm volatile ("membar #LoadStore | #StoreStore \n\t" : : : "memory");
00100 /* membars after or before atomic_ops or atomic_setget -> use these or
00101  *  mb_<atomic_op_name>() if you need a memory barrier in one of these
00102  *  situations (on some archs where the atomic operations imply memory
00103  *   barriers is better to use atomic_op_x(); membar_atomic_op() then
00104  *    atomic_op_x(); membar()) */
00105 #define membar_atomic_op()                              membar()
00106 #define membar_atomic_setget()                  membar()
00107 #define membar_write_atomic_op()                membar_write()
00108 #define membar_write_atomic_setget()    membar_write()
00109 #define membar_read_atomic_op()                 membar_read()
00110 #define membar_read_atomic_setget()             membar_read()
00111 #endif /* NOSMP */
00112 
00113 
00114 
00115 /* 32 bit version, op should store the result in %1, and use %0 as input,
00116  *  both %0 and %1 are modified */
00117 #define ATOMIC_ASM_OP_int(op)\
00118         "   ldsw [%3], %0 \n\t"  /* signed or lduw? */ \
00119         "1: " op " \n\t" \
00120         "   cas  [%3], %0, %1 \n\t" \
00121         "   cmp %0, %1 \n\t" \
00122         "   bne,a,pn  %%icc, 1b \n\t"  /* predict not taken, annul */ \
00123         "   mov %1, %0\n\t"  /* delay slot */
00124 
00125 #ifdef SPARC64_MODE
00126 /* 64 bit version, same as above */
00127 #define ATOMIC_ASM_OP_long(op)\
00128         "   ldx [%3], %0 \n\t" \
00129         "1: " op " \n\t" \
00130         "   casx  [%3], %0, %1 \n\t" \
00131         "   cmp %0, %1 \n\t" \
00132         "   bne,a,pn  %%xcc, 1b \n\t"  /* predict not taken, annul */ \
00133         "   mov %1, %0\n\t"  /* delay slot */
00134         
00135 #else /* no SPARC64_MODE => 32bit mode on a sparc64*/
00136 #define ATOMIC_ASM_OP_long(op) ATOMIC_ASM_OP_int(op)
00137 #endif
00138 
00139 #define ATOMIC_FUNC_DECL(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00140         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
00141         { \
00142                 P_TYPE ret, tmp; \
00143                 asm volatile( \
00144                         ATOMIC_ASM_OP_##P_TYPE(OP) \
00145                         : "=&r"(ret), "=&r"(tmp), "=m"(*var) : "r"(var) : "cc" \
00146                         ); \
00147                 return RET_EXPR; \
00148         }
00149 
00150 
00151 /* same as above, but takes an extra param, v, which goes in %4 */
00152 #define ATOMIC_FUNC_DECL1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00153         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
00154                                                                                                                         P_TYPE v) \
00155         { \
00156                 P_TYPE ret, tmp; \
00157                 asm volatile( \
00158                         ATOMIC_ASM_OP_##P_TYPE(OP) \
00159                         : "=&r"(ret), "=&r"(tmp), "=m"(*var) : "r"(var), "r"(v) : "cc" \
00160                         ); \
00161                 return RET_EXPR; \
00162         }
00163 
00164 /* same as above, but uses a short 1 op sequence 
00165  * %2 (or %1) is var, %0 is  v and return (ret)*/
00166 #define ATOMIC_FUNC_DECL1_RAW(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00167         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
00168                                                                                                                         P_TYPE v) \
00169         { \
00170                 P_TYPE ret; \
00171                 asm volatile( \
00172                         OP "\n\t" \
00173                         : "=&r"(ret), "=m"(*var) : "r"(var), "0"(v) : "cc" \
00174                         ); \
00175                 return RET_EXPR; \
00176         }
00177 
00178 /* same as above, but takes two extra params, v, which goes in %4
00179  * and uses a short 1 op sequence:
00180  * %2 (or %1) is var, %3 is v1 and %0 is v2 & result (ret) */
00181 #define ATOMIC_FUNC_DECL2_CAS(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00182         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
00183                                                                                                         P_TYPE v1, P_TYPE v2) \
00184         { \
00185                 P_TYPE ret; \
00186                 asm volatile( \
00187                         OP "\n\t" \
00188                         : "=&r"(ret), "=m"(*var) : "r"(var), "r"(v1), "0"(v2) : "cc" \
00189                         ); \
00190                 return RET_EXPR; \
00191         }
00192 
00193 
00194 
00195 ATOMIC_FUNC_DECL(inc,      "add  %0,  1, %1", int, void, /* no return */ )
00196 ATOMIC_FUNC_DECL(dec,      "sub  %0,  1, %1", int, void, /* no return */ )
00197 ATOMIC_FUNC_DECL1(and,     "and  %0, %4, %1", int, void, /* no return */ )
00198 ATOMIC_FUNC_DECL1(or,      "or   %0, %4, %1", int, void, /* no return */ )
00199 ATOMIC_FUNC_DECL(inc_and_test, "add   %0, 1, %1", int, int, ((ret+1)==0) )
00200 ATOMIC_FUNC_DECL(dec_and_test, "sub   %0, 1, %1", int, int, ((ret-1)==0) )
00201 /* deprecated but probably better then CAS for futexes */
00202 ATOMIC_FUNC_DECL1_RAW(get_and_set, "swap [%2], %0", int, int, ret)
00203 /*ATOMIC_FUNC_DECL1(get_and_set, "mov %4, %1" , int, int,  ret)*/
00204 ATOMIC_FUNC_DECL1(add,     "add  %0, %4, %1", int, int,  ret+v)
00205 ATOMIC_FUNC_DECL2_CAS(cmpxchg, "cas  [%2], %3, %0", int, int,  ret)
00206 
00207 
00208 ATOMIC_FUNC_DECL(inc,      "add  %0,  1, %1", long, void, /* no return */ )
00209 ATOMIC_FUNC_DECL(dec,      "sub  %0,  1, %1", long, void, /* no return */ )
00210 ATOMIC_FUNC_DECL1(and,     "and  %0, %4, %1", long, void, /* no return */ )
00211 ATOMIC_FUNC_DECL1(or,      "or   %0, %4, %1", long, void, /* no return */ )
00212 ATOMIC_FUNC_DECL(inc_and_test, "add   %0, 1, %1", long, long, ((ret+1)==0) )
00213 ATOMIC_FUNC_DECL(dec_and_test, "sub   %0, 1, %1", long, long, ((ret-1)==0) )
00214 ATOMIC_FUNC_DECL1(get_and_set, "mov %4, %1" , long, long,  ret)
00215 ATOMIC_FUNC_DECL1(add,     "add  %0, %4, %1", long, long,  ret+v)
00216 #ifdef SPARC64_MODE
00217 ATOMIC_FUNC_DECL2_CAS(cmpxchg, "casx  [%2], %3, %0", long, long,  ret)
00218 #else
00219 ATOMIC_FUNC_DECL2_CAS(cmpxchg, "cas   [%2], %3, %0", long, long,  ret)
00220 #endif
00221 
00222 
00223 #define atomic_inc(var) atomic_inc_int(&(var)->val)
00224 #define atomic_dec(var) atomic_dec_int(&(var)->val)
00225 #define atomic_and(var, mask) atomic_and_int(&(var)->val, (mask))
00226 #define atomic_or(var, mask)  atomic_or_int(&(var)->val, (mask))
00227 #define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
00228 #define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
00229 #define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
00230 #define atomic_add(var, i) atomic_add_int(&(var)->val, i)
00231 #define atomic_cmpxchg(var, old, new_v) \
00232         atomic_cmpxchg_int(&(var)->val, old, new_v)
00233 
00234 
00235 
00236 /* with integrated membar */
00237 
00238 #define mb_atomic_set_int(v, i) \
00239         do{ \
00240                 membar(); \
00241                 atomic_set_int(v, i); \
00242         }while(0)
00243 
00244 
00245 
00246 inline static int mb_atomic_get_int(volatile int* v)
00247 {
00248         membar();
00249         return atomic_get_int(v);
00250 }
00251 
00252 
00253 #define mb_atomic_inc_int(v) \
00254         do{ \
00255                 membar(); \
00256                 atomic_inc_int(v); \
00257         }while(0)
00258 
00259 #define mb_atomic_dec_int(v) \
00260         do{ \
00261                 membar(); \
00262                 atomic_dec_int(v); \
00263         }while(0)
00264 
00265 #define mb_atomic_or_int(v, m) \
00266         do{ \
00267                 membar(); \
00268                 atomic_or_int(v, m); \
00269         }while(0)
00270 
00271 #define mb_atomic_and_int(v, m) \
00272         do{ \
00273                 membar(); \
00274                 atomic_and_int(v, m); \
00275         }while(0)
00276 
00277 inline static int mb_atomic_inc_and_test_int(volatile int* v)
00278 {
00279         membar();
00280         return atomic_inc_and_test_int(v);
00281 }
00282 
00283 inline static int mb_atomic_dec_and_test_int(volatile int* v)
00284 {
00285         membar();
00286         return atomic_dec_and_test_int(v);
00287 }
00288 
00289 
00290 inline static int mb_atomic_get_and_set_int(volatile int* v, int i)
00291 {
00292         membar();
00293         return atomic_get_and_set_int(v, i);
00294 }
00295 
00296 inline static int mb_atomic_cmpxchg_int(volatile int* v, int o, int n)
00297 {
00298         membar();
00299         return atomic_cmpxchg_int(v, o, n);
00300 }
00301 
00302 inline static int mb_atomic_add_int(volatile int* v, int i)
00303 {
00304         membar();
00305         return atomic_add_int(v, i);
00306 }
00307 
00308 
00309 
00310 #define mb_atomic_set_long(v, i) \
00311         do{ \
00312                 membar(); \
00313                 atomic_set_long(v, i); \
00314         }while(0)
00315 
00316 
00317 
00318 inline static long mb_atomic_get_long(volatile long* v)
00319 {
00320         membar();
00321         return atomic_get_long(v);
00322 }
00323 
00324 
00325 #define mb_atomic_inc_long(v) \
00326         do{ \
00327                 membar(); \
00328                 atomic_inc_long(v); \
00329         }while(0)
00330 
00331 
00332 #define mb_atomic_dec_long(v) \
00333         do{ \
00334                 membar(); \
00335                 atomic_dec_long(v); \
00336         }while(0)
00337 
00338 #define mb_atomic_or_long(v, m) \
00339         do{ \
00340                 membar(); \
00341                 atomic_or_long(v, m); \
00342         }while(0)
00343 
00344 #define mb_atomic_and_long(v, m) \
00345         do{ \
00346                 membar(); \
00347                 atomic_and_long(v, m); \
00348         }while(0)
00349 
00350 inline static long mb_atomic_inc_and_test_long(volatile long* v)
00351 {
00352         membar();
00353         return atomic_inc_and_test_long(v);
00354 }
00355 
00356 inline static long mb_atomic_dec_and_test_long(volatile long* v)
00357 {
00358         membar();
00359         return atomic_dec_and_test_long(v);
00360 }
00361 
00362 
00363 inline static long mb_atomic_get_and_set_long(volatile long* v, long l)
00364 {
00365         membar();
00366         return atomic_get_and_set_long(v, l);
00367 }
00368 
00369 inline static long mb_atomic_cmpxchg_long(volatile long* v, long o, long n)
00370 {
00371         membar();
00372         return atomic_cmpxchg_long(v, o, n);
00373 }
00374 
00375 inline static long mb_atomic_add_long(volatile long* v, long i)
00376 {
00377         membar();
00378         return atomic_add_long(v, i);
00379 }
00380 
00381 
00382 #define mb_atomic_inc(var) mb_atomic_inc_int(&(var)->val)
00383 #define mb_atomic_dec(var) mb_atomic_dec_int(&(var)->val)
00384 #define mb_atomic_and(var, mask) mb_atomic_and_int(&(var)->val, (mask))
00385 #define mb_atomic_or(var, mask)  mb_atomic_or_int(&(var)->val, (mask))
00386 #define mb_atomic_dec_and_test(var) mb_atomic_dec_and_test_int(&(var)->val)
00387 #define mb_atomic_inc_and_test(var) mb_atomic_inc_and_test_int(&(var)->val)
00388 #define mb_atomic_get(var)      mb_atomic_get_int(&(var)->val)
00389 #define mb_atomic_set(var, i)   mb_atomic_set_int(&(var)->val, i)
00390 #define mb_atomic_get_and_set(var, i) mb_atomic_get_and_set_int(&(var)->val, i)
00391 #define mb_atomic_cmpxchg(var, o, n) mb_atomic_cmpxchg_int(&(var)->val, o, n)
00392 #define mb_atomic_add(var, i) mb_atomic_add_int(&(var)->val, i)
00393 
00394 
00395 #endif