$search
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 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