atomic_mips2.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 
00034 /* 
00035  * History:
00036  * --------
00037  *  2006-03-08  created by andrei
00038  *  2007-05-10  added atomic_add & atomic_cmpxchg (andrei)
00039  *  2007-05-29  added membar_depends(), membar_*_atomic_op and
00040  *                membar_*_atomic_setget (andrei)
00041  */
00042 
00043 
00044 #ifndef _atomic_mips2_h
00045 #define _atomic_mips2_h
00046 
00047 #define HAVE_ASM_INLINE_ATOMIC_OPS
00048 #define HAVE_ASM_INLINE_MEMBAR
00049 
00050 #ifdef __CPU_mips64
00051 #warning mips64 atomic code was not tested, please report problems to \
00052                 serdev@iptel.org or andrei@iptel.org
00053 #endif
00054 
00055 #ifdef NOSMP
00056 #define membar() asm volatile ("" : : : "memory") /* gcc do not cache barrier*/
00057 #define membar_read()  membar()
00058 #define membar_write() membar()
00059 #define membar_depends()  do {} while(0) /* really empty, not even a cc bar. */
00060 /* lock barriers: empty, not needed for NOSMP; the lock/unlock should already
00061  * contain gcc barriers*/
00062 #define membar_enter_lock() do {} while(0)
00063 #define membar_leave_lock() do {} while(0)
00064 /* membars after or before atomic_ops or atomic_setget -> use these or
00065  *  mb_<atomic_op_name>() if you need a memory barrier in one of these
00066  *  situations (on some archs where the atomic operations imply memory
00067  *   barriers is better to use atomic_op_x(); membar_atomic_op() then
00068  *    atomic_op_x(); membar()) */
00069 #define membar_atomic_op()                              membar()
00070 #define membar_atomic_setget()                  membar()
00071 #define membar_write_atomic_op()                membar_write()
00072 #define membar_write_atomic_setget()    membar_write()
00073 #define membar_read_atomic_op()                 membar_read()
00074 #define membar_read_atomic_setget()             membar_read()
00075 
00076 #else
00077 
00078 #define membar() \
00079         asm volatile( \
00080                         ".set push \n\t" \
00081                         ".set noreorder \n\t" \
00082                         ".set mips2 \n\t" \
00083                         "    sync\n\t" \
00084                         ".set pop \n\t" \
00085                         : : : "memory" \
00086                         ) 
00087 
00088 #define membar_read()  membar()
00089 #define membar_write() membar()
00090 #define membar_depends()  do {} while(0) /* really empty, not even a cc bar. */
00091 #define membar_enter_lock() membar()
00092 #define membar_leave_lock() membar()
00093 /* membars after or before atomic_ops or atomic_setget -> use these or
00094  *  mb_<atomic_op_name>() if you need a memory barrier in one of these
00095  *  situations (on some archs where the atomic operations imply memory
00096  *   barriers is better to use atomic_op_x(); membar_atomic_op() then
00097  *    atomic_op_x(); membar()) */
00098 #define membar_atomic_op()                              membar()
00099 #define membar_atomic_setget()                  membar()
00100 #define membar_write_atomic_op()                membar_write()
00101 #define membar_write_atomic_setget()    membar_write()
00102 #define membar_read_atomic_op()                 membar_read()
00103 #define membar_read_atomic_setget()             membar_read()
00104 
00105 #endif /* NOSMP */
00106 
00107 
00108 
00109 /* main asm block */
00110 #define ATOMIC_ASM_OP_int(op) \
00111                         ".set push \n\t" \
00112                         ".set noreorder \n\t" \
00113                         ".set mips2 \n\t" \
00114                         "1:   ll %1, %0 \n\t" \
00115                         "     " op "\n\t" \
00116                         "     sc %2, %0 \n\t" \
00117                         "     beqz %2, 1b \n\t" \
00118                         "     nop \n\t" /* delay slot */ \
00119                         ".set pop \n\t" 
00120 
00121 #ifdef __CPU_mips64
00122 #define ATOMIC_ASM_OP_long(op) \
00123                         ".set push \n\t" \
00124                         ".set noreorder \n\t" \
00125                         "1:   lld %1, %0 \n\t" \
00126                         "     " op "\n\t" \
00127                         "     scd %2, %0 \n\t" \
00128                         "     beqz %2, 1b \n\t" \
00129                         "     nop \n\t" /* delay slot */ \
00130                         ".set pop \n\t" 
00131 #else /* ! __CPU_mips64 => __CPU_mips2 or __CPU_mips & MIPS_HAS_LLSC */
00132 #define ATOMIC_ASM_OP_long(op) ATOMIC_ASM_OP_int(op)
00133 #endif
00134 
00135 
00136 #define ATOMIC_FUNC_DECL(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00137         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
00138         { \
00139                 P_TYPE ret, tmp; \
00140                 asm volatile( \
00141                         ATOMIC_ASM_OP_##P_TYPE(OP) \
00142                         : "=m"(*var), "=&r"(ret), "=&r"(tmp)  \
00143                         : "m"(*var) \
00144                          \
00145                         ); \
00146                 return RET_EXPR; \
00147         }
00148 
00149 
00150 /* same as above, but with CT in %3 */
00151 #define ATOMIC_FUNC_DECL_CT(NAME, OP, CT, P_TYPE, RET_TYPE, RET_EXPR) \
00152         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
00153         { \
00154                 P_TYPE ret, tmp; \
00155                 asm volatile( \
00156                         ATOMIC_ASM_OP_##P_TYPE(OP) \
00157                         : "=m"(*var), "=&r"(ret), "=&r"(tmp)  \
00158                         : "r"((CT)), "m"(*var) \
00159                          \
00160                         ); \
00161                 return RET_EXPR; \
00162         }
00163 
00164 
00165 /* takes an extra param, i which goes in %3 */
00166 #define ATOMIC_FUNC_DECL1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00167         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
00168                                                                                                                 P_TYPE i) \
00169         { \
00170                 P_TYPE ret, tmp; \
00171                 asm volatile( \
00172                         ATOMIC_ASM_OP_##P_TYPE(OP) \
00173                         : "=m"(*var), "=&r"(ret), "=&r"(tmp)  \
00174                         : "r"((i)), "m"(*var) \
00175                          \
00176                         ); \
00177                 return RET_EXPR; \
00178         }
00179 
00180 
00181 /* takes an extra param, like above, but i  goes in %2 */
00182 #define ATOMIC_FUNC_DECL2(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00183         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
00184                                                                                                                 P_TYPE i) \
00185         { \
00186                 P_TYPE ret; \
00187                 asm volatile( \
00188                         ATOMIC_ASM_OP_##P_TYPE(OP) \
00189                         : "=m"(*var), "=&r"(ret), "+&r"(i)  \
00190                         : "m"(*var) \
00191                          \
00192                         ); \
00193                 return RET_EXPR; \
00194         }
00195 
00196 
00197 /* %0=var, %1=*var, %2=new, %3=old :
00198  * ret=*var; if *var==old  then *var=new; return ret
00199  * => if succesfull (changed var to new)  ret==old */
00200 #define ATOMIC_CMPXCHG_DECL(NAME, P_TYPE) \
00201         inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
00202                                                                                                                 P_TYPE old, \
00203                                                                                                                 P_TYPE new_v) \
00204         { \
00205                 asm volatile( \
00206                         ATOMIC_ASM_OP_##P_TYPE("bne %1, %3, 2f \n\t nop") \
00207                         "2:    \n\t" \
00208                         : "=m"(*var), "=&r"(old), "=r"(new_v)  \
00209                         : "r"(old), "m"(*var), "2"(new_v) \
00210                          \
00211                         ); \
00212                 return old; \
00213         }
00214 
00215 ATOMIC_FUNC_DECL(inc,      "addiu %2, %1, 1", int, void, /* no return */ )
00216 ATOMIC_FUNC_DECL_CT(dec,   "subu %2, %1, %3", 1,  int, void, /* no return */ )
00217 ATOMIC_FUNC_DECL1(and, "and %2, %1, %3", int, void, /* no return */ )
00218 ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", int, void,  /* no return */ )
00219 ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", int, int, (ret+1)==0 )
00220 ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1, int, int, (ret-1)==0 )
00221 ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, int, int, ret )
00222 ATOMIC_CMPXCHG_DECL(cmpxchg, int)
00223 ATOMIC_FUNC_DECL1(add, "addu %2, %1, %3 \n\t move %1, %2", int, int, ret )
00224 
00225 #ifdef __CPU_mips64
00226 
00227 ATOMIC_FUNC_DECL(inc,      "daddiu %2, %1, 1", long, void, /* no return */ )
00228 ATOMIC_FUNC_DECL_CT(dec,   "dsubu %2, %1, %3", 1,  long, void, /* no return */ )
00229 ATOMIC_FUNC_DECL1(and, "and %2, %1, %3", long, void, /* no return */ )
00230 ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", long, void,  /* no return */ )
00231 ATOMIC_FUNC_DECL(inc_and_test, "daddiu %2, %1, 1", long, long, (ret+1)==0 )
00232 ATOMIC_FUNC_DECL_CT(dec_and_test, "dsubu %2, %1, %3", 1,long, long, (ret-1)==0 )
00233 ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
00234 ATOMIC_CMPXCHG_DECL(cmpxchg, long)
00235 ATOMIC_FUNC_DECL1(add, "daddu %2, %1, %3 \n\t move %1, %2", long, long, ret )
00236 
00237 #else /* ! __CPU_mips64 => __CPU_mips2 or __CPU_mips */
00238 
00239 ATOMIC_FUNC_DECL(inc,      "addiu %2, %1, 1", long, void, /* no return */ )
00240 ATOMIC_FUNC_DECL_CT(dec,   "subu %2, %1, %3", 1,  long, void, /* no return */ )
00241 ATOMIC_FUNC_DECL1(and, "and %2, %1, %3", long, void, /* no return */ )
00242 ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", long, void,  /* no return */ )
00243 ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", long, long, (ret+1)==0 )
00244 ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1,long, long, (ret-1)==0 )
00245 ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
00246 ATOMIC_CMPXCHG_DECL(cmpxchg, long)
00247 ATOMIC_FUNC_DECL1(add, "addu %2, %1, %3 \n\t move %1, %2", long, long, ret )
00248 
00249 #endif /* __CPU_mips64 */
00250 
00251 #define atomic_inc(var) atomic_inc_int(&(var)->val)
00252 #define atomic_dec(var) atomic_dec_int(&(var)->val)
00253 #define atomic_and(var, mask) atomic_and_int(&(var)->val, (mask))
00254 #define atomic_or(var, mask)  atomic_or_int(&(var)->val, (mask))
00255 #define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
00256 #define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
00257 #define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
00258 #define atomic_add(var, i) atomic_add_int(&(var)->val, i)
00259 #define atomic_cmpxchg(var, old, new_v)  \
00260         atomic_cmpxchg_int(&(var)->val, old, new_v)
00261 
00262 
00263 /* with integrated membar */
00264 
00265 #define mb_atomic_set_int(v, i) \
00266         do{ \
00267                 membar(); \
00268                 atomic_set_int(v, i); \
00269         }while(0)
00270 
00271 
00272 
00273 inline static int mb_atomic_get_int(volatile int* v)
00274 {
00275         membar();
00276         return atomic_get_int(v);
00277 }
00278 
00279 
00280 #define mb_atomic_inc_int(v) \
00281         do{ \
00282                 membar(); \
00283                 atomic_inc_int(v); \
00284         }while(0)
00285 
00286 #define mb_atomic_dec_int(v) \
00287         do{ \
00288                 membar(); \
00289                 atomic_dec_int(v); \
00290         }while(0)
00291 
00292 #define mb_atomic_or_int(v, m) \
00293         do{ \
00294                 membar(); \
00295                 atomic_or_int(v, m); \
00296         }while(0)
00297 
00298 #define mb_atomic_and_int(v, m) \
00299         do{ \
00300                 membar(); \
00301                 atomic_and_int(v, m); \
00302         }while(0)
00303 
00304 inline static int mb_atomic_inc_and_test_int(volatile int* v)
00305 {
00306         membar();
00307         return atomic_inc_and_test_int(v);
00308 }
00309 
00310 inline static int mb_atomic_dec_and_test_int(volatile int* v)
00311 {
00312         membar();
00313         return atomic_dec_and_test_int(v);
00314 }
00315 
00316 
00317 inline static int mb_atomic_get_and_set_int(volatile int* v, int i)
00318 {
00319         membar();
00320         return atomic_get_and_set_int(v, i);
00321 }
00322 
00323 inline static int mb_atomic_cmpxchg_int(volatile int* v, int o, int n)
00324 {
00325         membar();
00326         return atomic_cmpxchg_int(v, o, n);
00327 }
00328 
00329 inline static int mb_atomic_add_int(volatile int* v, int i)
00330 {
00331         membar();
00332         return atomic_add_int(v, i);
00333 }
00334 
00335 
00336 #define mb_atomic_set_long(v, i) \
00337         do{ \
00338                 membar(); \
00339                 atomic_set_long(v, i); \
00340         }while(0)
00341 
00342 
00343 
00344 inline static long mb_atomic_get_long(volatile long* v)
00345 {
00346         membar();
00347         return atomic_get_long(v);
00348 }
00349 
00350 
00351 #define mb_atomic_inc_long(v) \
00352         do{ \
00353                 membar(); \
00354                 atomic_inc_long(v); \
00355         }while(0)
00356 
00357 
00358 #define mb_atomic_dec_long(v) \
00359         do{ \
00360                 membar(); \
00361                 atomic_dec_long(v); \
00362         }while(0)
00363 
00364 #define mb_atomic_or_long(v, m) \
00365         do{ \
00366                 membar(); \
00367                 atomic_or_long(v, m); \
00368         }while(0)
00369 
00370 #define mb_atomic_and_long(v, m) \
00371         do{ \
00372                 membar(); \
00373                 atomic_and_long(v, m); \
00374         }while(0)
00375 
00376 inline static long mb_atomic_inc_and_test_long(volatile long* v)
00377 {
00378         membar();
00379         return atomic_inc_and_test_long(v);
00380 }
00381 
00382 inline static long mb_atomic_dec_and_test_long(volatile long* v)
00383 {
00384         membar();
00385         return atomic_dec_and_test_long(v);
00386 }
00387 
00388 
00389 inline static long mb_atomic_get_and_set_long(volatile long* v, long l)
00390 {
00391         membar();
00392         return atomic_get_and_set_long(v, l);
00393 }
00394 
00395 inline static long mb_atomic_cmpxchg_long(volatile long* v, long o, long n)
00396 {
00397         membar();
00398         return atomic_cmpxchg_long(v, o, n);
00399 }
00400 
00401 inline static long mb_atomic_add_long(volatile long* v, long i)
00402 {
00403         membar();
00404         return atomic_add_long(v, i);
00405 }
00406 
00407 
00408 #define mb_atomic_inc(var) mb_atomic_inc_int(&(var)->val)
00409 #define mb_atomic_dec(var) mb_atomic_dec_int(&(var)->val)
00410 #define mb_atomic_and(var, mask) mb_atomic_and_int(&(var)->val, (mask))
00411 #define mb_atomic_or(var, mask)  mb_atomic_or_int(&(var)->val, (mask))
00412 #define mb_atomic_dec_and_test(var) mb_atomic_dec_and_test_int(&(var)->val)
00413 #define mb_atomic_inc_and_test(var) mb_atomic_inc_and_test_int(&(var)->val)
00414 #define mb_atomic_get(var)      mb_atomic_get_int(&(var)->val)
00415 #define mb_atomic_set(var, i)   mb_atomic_set_int(&(var)->val, i)
00416 #define mb_atomic_get_and_set(var, i) mb_atomic_get_and_set_int(&(var)->val, i)
00417 #define mb_atomic_cmpxchg(var, o, n) mb_atomic_cmpxchg_int(&(var)->val, o, n)
00418 #define mb_atomic_add(var, i) mb_atomic_add_int(&(var)->val, i)
00419 
00420 #endif