oro_atomic.h

Go to the documentation of this file.
00001 /***************************************************************************
00002   tag: FMTC  Tue Mar 11 21:49:19 CET 2008  oro_atomic.h
00003 
00004                         oro_atomic.h -  description
00005                            -------------------
00006     begin                : Tue March 11 2008
00007     copyright            : (C) 2008 FMTC
00008     email                : peter.soetens@fmtc.be
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00039 #ifndef __ARCH_powerpc_ORO_ATOMIC__
00040 #define __ARCH_powerpc_ORO_ATOMIC__
00041 
00042 /* Klaas Gadeyne, copied the 32 bit part from
00043  * /usr/src/linux-2.6.16/include/asm-powerpc/atomic.h
00044  * /usr/src/linux-2.6.16/include/asm-powerpc/asm-compat.h
00045  * /usr/src/linux-2.6.16/include/asm-powerpc/synch.h
00046  * So will currently only work for 32 bit ppc
00047  */
00048 
00049 // ==================================================
00050 // asm/synch.h
00051 #ifdef _cplusplus
00052 extern "C"
00053 {
00054 #endif // _cplusplus
00055 
00056 #ifdef __SUBARCH_HAS_LWSYNC
00057 #    define LWSYNC  lwsync
00058 #else
00059 #    define LWSYNC  sync
00060 #endif
00061 
00062 #define ISYNC_ON_SMP
00063 #define LWSYNC_ON_SMP
00064 
00065 static inline void eieio(void)
00066 {
00067   __asm__ __volatile__ ("eieio" : : : "memory");
00068 }
00069 
00070 static inline void isync(void)
00071 {
00072   __asm__ __volatile__ ("isync" : : : "memory");
00073 }
00074 
00075 // ==================================================
00076 // asm/asm-compat.h
00077 
00078 #ifdef __ASSEMBLY__
00079 #  define stringify_in_c(...)   __VA_ARGS__
00080 #  define ASM_CONST(x)          x
00081 #else
00082 /* This version of stringify will deal with commas... */
00083 #  define __stringify_in_c(...) #__VA_ARGS__
00084 #  define stringify_in_c(...)   __stringify_in_c(__VA_ARGS__) " "
00085 #  define __ASM_CONST(x)        x##UL
00086 #  define ASM_CONST(x)          __ASM_CONST(x)
00087 #endif
00088 
00089 /* operations for longs and pointers */
00090 #define PPC_LL          stringify_in_c(lwz)
00091 #define PPC_STL         stringify_in_c(stw)
00092 #define PPC_LCMPI       stringify_in_c(cmpwi)
00093 #define PPC_LONG        stringify_in_c(.long)
00094 #define PPC_TLNEI       stringify_in_c(twnei)
00095 #define PPC_LLARX       stringify_in_c(lwarx)
00096 #define PPC_STLCX       stringify_in_c(stwcx.)
00097 #define PPC_CNTLZL      stringify_in_c(cntlzw)
00098 
00099 #ifdef CONFIG_IBM405_ERR77
00100 /* Erratum #77 on the 405 means we need a sync or dcbt before every
00101  * stwcx.  The old ATOMIC_SYNC_FIX covered some but not all of this.
00102  */
00103 #define PPC405_ERR77(ra,rb)     stringify_in_c(dcbt     ra, rb;)
00104 #define PPC405_ERR77_SYNC       stringify_in_c(sync;)
00105 #else
00106 #define PPC405_ERR77(ra,rb)
00107 #define PPC405_ERR77_SYNC
00108 #endif
00109 
00110 // ==================================================
00111 // asm/atomic.h
00112 
00113 /*
00114  * PowerPC atomic operations
00115  */
00116 
00117 typedef struct { volatile int counter; } oro_atomic_t;
00118 
00119 #define ORO_ATOMIC_INIT(i)    { (i) }
00120 #define ORO_ATOMIC_SETUP  oro_atomic_set
00121 #define ORO_ATOMIC_CLEANUP(v) 
00122 
00123 #define oro_atomic_read(v)    ((v)->counter)
00124 #define oro_atomic_set(v,i)   (((v)->counter) = (i))
00125 
00126   static __inline__ void oro_atomic_add(oro_atomic_t *v, int n)
00127 {
00128   int t;
00129 
00130   __asm__ __volatile__(
00131 "1: lwarx %0,0,%3   # oro_atomic_add\n\
00132   add %0,%2,%0\n"
00133   PPC405_ERR77(0,%3)
00134 " stwcx.  %0,0,%3 \n\
00135   bne-  1b"
00136   : "=&r" (t), "=m" (v->counter)
00137   : "r" (a), "r" (&v->counter), "m" (v->counter)
00138   : "cc");
00139 }
00140 
00141   static __inline__ int oro_atomic_add_return(oro_atomic_t *v, int n)
00142 {
00143   int t;
00144 
00145   __asm__ __volatile__(
00146   LWSYNC_ON_SMP
00147 "1: lwarx %0,0,%2   # oro_atomic_add_return\n\
00148   add %0,%1,%0\n"
00149   PPC405_ERR77(0,%2)
00150 " stwcx.  %0,0,%2 \n\
00151   bne-  1b"
00152   ISYNC_ON_SMP
00153   : "=&r" (t)
00154   : "r" (a), "r" (&v->counter)
00155   : "cc", "memory");
00156 
00157   return t;
00158 }
00159 
00160 #define oro_atomic_add_negative(a, v) (oro_atomic_add_return((a), (v)) < 0)
00161 
00162 static __inline__ void oro_atomic_sub(int a, oro_atomic_t *v)
00163 {
00164   int t;
00165 
00166   __asm__ __volatile__(
00167 "1: lwarx %0,0,%3   # oro_atomic_sub\n\
00168   subf  %0,%2,%0\n"
00169   PPC405_ERR77(0,%3)
00170 " stwcx.  %0,0,%3 \n\
00171   bne-  1b"
00172   : "=&r" (t), "=m" (v->counter)
00173   : "r" (a), "r" (&v->counter), "m" (v->counter)
00174   : "cc");
00175 }
00176 
00177 static __inline__ int oro_atomic_sub_return(oro_atomic_t *v, int n)
00178 {
00179   int t;
00180 
00181   __asm__ __volatile__(
00182   LWSYNC_ON_SMP
00183 "1: lwarx %0,0,%2   # oro_atomic_sub_return\n\
00184   subf  %0,%1,%0\n"
00185   PPC405_ERR77(0,%2)
00186 " stwcx.  %0,0,%2 \n\
00187   bne-  1b"
00188   ISYNC_ON_SMP
00189   : "=&r" (t)
00190   : "r" (a), "r" (&v->counter)
00191   : "cc", "memory");
00192 
00193   return t;
00194 }
00195 
00196 static __inline__ void oro_atomic_inc(oro_atomic_t *v)
00197 {
00198   int t;
00199 
00200   __asm__ __volatile__(
00201 "1: lwarx %0,0,%2   # oro_atomic_inc\n\
00202   addic %0,%0,1\n"
00203   PPC405_ERR77(0,%2)
00204 " stwcx.  %0,0,%2 \n\
00205   bne-  1b"
00206   : "=&r" (t), "=m" (v->counter)
00207   : "r" (&v->counter), "m" (v->counter)
00208   : "cc");
00209 }
00210 
00211 static __inline__ int oro_atomic_inc_return(oro_atomic_t *v)
00212 {
00213   int t;
00214 
00215   __asm__ __volatile__(
00216   LWSYNC_ON_SMP
00217 "1: lwarx %0,0,%1   # oro_atomic_inc_return\n\
00218   addic %0,%0,1\n"
00219   PPC405_ERR77(0,%1)
00220 " stwcx.  %0,0,%1 \n\
00221   bne-  1b"
00222   ISYNC_ON_SMP
00223   : "=&r" (t)
00224   : "r" (&v->counter)
00225   : "cc", "memory");
00226 
00227   return t;
00228 }
00229 
00230 /*
00231  * oro_atomic_inc_and_test - increment and test
00232  * @v: pointer of type oro_atomic_t
00233  *
00234  * Atomically increments @v by 1
00235  * and returns true if the result is zero, or false for all
00236  * other cases.
00237  */
00238 #define oro_atomic_inc_and_test(v) (oro_atomic_inc_return(v) == 0)
00239 
00240 static __inline__ void oro_atomic_dec(oro_atomic_t *v)
00241 {
00242   int t;
00243 
00244   __asm__ __volatile__(
00245 "1: lwarx %0,0,%2   # oro_atomic_dec\n\
00246   addic %0,%0,-1\n"
00247   PPC405_ERR77(0,%2)\
00248 " stwcx.  %0,0,%2\n\
00249   bne-  1b"
00250   : "=&r" (t), "=m" (v->counter)
00251   : "r" (&v->counter), "m" (v->counter)
00252   : "cc");
00253 }
00254 
00255 static __inline__ int oro_atomic_dec_return(oro_atomic_t *v)
00256 {
00257   int t;
00258 
00259   __asm__ __volatile__(
00260   LWSYNC_ON_SMP
00261 "1: lwarx %0,0,%1   # oro_atomic_dec_return\n\
00262   addic %0,%0,-1\n"
00263   PPC405_ERR77(0,%1)
00264 " stwcx.  %0,0,%1\n\
00265   bne-  1b"
00266   ISYNC_ON_SMP
00267   : "=&r" (t)
00268   : "r" (&v->counter)
00269   : "cc", "memory");
00270 
00271   return t;
00272 }
00273 
00274 #define oro_atomic_oro_cmpxchg(v, o, n) ((int)oro_cmpxchg(&((v)->counter), (o), (n)))
00275 #define oro_atomic_xchg(v, new) (xchg(&((v)->counter), new))
00276 
00277 /**
00278  * oro_atomic_add_unless - add unless the number is a given value
00279  * @v: pointer of type oro_atomic_t
00280  * @a: the amount to add to v...
00281  * @u: ...unless v is equal to u.
00282  *
00283  * Atomically adds @a to @v, so long as it was not @u.
00284  * Returns non-zero if @v was not @u, and zero otherwise.
00285  */
00286 #define oro_atomic_add_unless(v, a, u)      \
00287 ({              \
00288   int c, old;         \
00289   c = oro_atomic_read(v);       \
00290   for (;;) {          \
00291     if (unlikely(c == (u)))     \
00292       break;        \
00293     old = oro_atomic_oro_cmpxchg((v), c, c + (a));  \
00294     if (likely(old == c))     \
00295       break;        \
00296     c = old;        \
00297   }           \
00298   c != (u);         \
00299 })
00300 #define oro_atomic_inc_not_zero(v) oro_atomic_add_unless((v), 1, 0)
00301 
00302 #define oro_atomic_sub_and_test(a, v) (oro_atomic_sub_return((a), (v)) == 0)
00303 #define oro_atomic_dec_and_test(v)    (oro_atomic_dec_return((v)) == 0)
00304 
00305 /*
00306  * Atomically test *v and decrement if it is greater than 0.
00307  * The function returns the old value of *v minus 1.
00308  */
00309 static __inline__ int oro_atomic_dec_if_positive(oro_atomic_t *v)
00310 {
00311   int t;
00312 
00313   __asm__ __volatile__(
00314   LWSYNC_ON_SMP
00315 "1: lwarx %0,0,%1   # oro_atomic_dec_if_positive\n\
00316   addic.  %0,%0,-1\n\
00317   blt-  2f\n"
00318   PPC405_ERR77(0,%1)
00319 " stwcx.  %0,0,%1\n\
00320   bne-  1b"
00321   ISYNC_ON_SMP
00322   "\n\
00323 2:" : "=&r" (t)
00324   : "r" (&v->counter)
00325   : "cc", "memory");
00326 
00327   return t;
00328 }
00329 
00330 #define smp_mb__before_oro_atomic_dec()     smp_mb()
00331 #define smp_mb__after_oro_atomic_dec()      smp_mb()
00332 #define smp_mb__before_oro_atomic_inc()     smp_mb()
00333 #define smp_mb__after_oro_atomic_inc()      smp_mb()
00334 
00335 #undef ORO_LOCK
00336 
00337 #ifdef _cplusplus
00338 } // end extern "C"
00339 #endif // _cplusplus
00340 
00341 #endif // __ARCH_powerpc_ORO_ATOMIC__
00342 
Generated by  doxygen 1.6.3