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