Orocos Real-Time Toolkit  2.8.3
oro_atomic.h
Go to the documentation of this file.
1 /***************************************************************************
2  tag: FMTC Tue Mar 11 21:49:19 CET 2008 oro_atomic.h
3 
4  oro_atomic.h - description
5  -------------------
6  begin : Tue March 11 2008
7  copyright : (C) 2008 FMTC
8  email : peter.soetens@fmtc.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * Lesser General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 
39 #ifndef __ARCH_powerpc_ORO_ATOMIC__
40 #define __ARCH_powerpc_ORO_ATOMIC__
41 
42 /* Klaas Gadeyne, copied the 32 bit part from
43  * /usr/src/linux-2.6.16/include/asm-powerpc/atomic.h
44  * /usr/src/linux-2.6.16/include/asm-powerpc/asm-compat.h
45  * /usr/src/linux-2.6.16/include/asm-powerpc/synch.h
46  * So will currently only work for 32 bit ppc
47  */
48 
49 // ==================================================
50 // asm/synch.h
51 #ifdef _cplusplus
52 extern "C"
53 {
54 #endif // _cplusplus
55 
56 #ifdef __SUBARCH_HAS_LWSYNC
57 # define LWSYNC lwsync
58 #else
59 # define LWSYNC sync
60 #endif
61 
62 #define ISYNC_ON_SMP
63 #define LWSYNC_ON_SMP
64 
65 static inline void eieio(void)
66 {
67  __asm__ __volatile__ ("eieio" : : : "memory");
68 }
69 
70 static inline void isync(void)
71 {
72  __asm__ __volatile__ ("isync" : : : "memory");
73 }
74 
75 // ==================================================
76 // asm/asm-compat.h
77 
78 #ifdef __ASSEMBLY__
79 # define stringify_in_c(...) __VA_ARGS__
80 # define ASM_CONST(x) x
81 #else
82 /* This version of stringify will deal with commas... */
83 # define __stringify_in_c(...) #__VA_ARGS__
84 # define stringify_in_c(...) __stringify_in_c(__VA_ARGS__) " "
85 # define __ASM_CONST(x) x##UL
86 # define ASM_CONST(x) __ASM_CONST(x)
87 #endif
88 
89 /* operations for longs and pointers */
90 #define PPC_LL stringify_in_c(lwz)
91 #define PPC_STL stringify_in_c(stw)
92 #define PPC_LCMPI stringify_in_c(cmpwi)
93 #define PPC_LONG stringify_in_c(.long)
94 #define PPC_TLNEI stringify_in_c(twnei)
95 #define PPC_LLARX stringify_in_c(lwarx)
96 #define PPC_STLCX stringify_in_c(stwcx.)
97 #define PPC_CNTLZL stringify_in_c(cntlzw)
98 
99 #ifdef CONFIG_IBM405_ERR77
100 /* Erratum #77 on the 405 means we need a sync or dcbt before every
101  * stwcx. The old ATOMIC_SYNC_FIX covered some but not all of this.
102  */
103 #define PPC405_ERR77(ra,rb) stringify_in_c(dcbt ra, rb;)
104 #define PPC405_ERR77_SYNC stringify_in_c(sync;)
105 #else
106 #define PPC405_ERR77(ra,rb)
107 #define PPC405_ERR77_SYNC
108 #endif
109 
110 // ==================================================
111 // asm/atomic.h
112 
113 /*
114  * PowerPC atomic operations
115  */
116 
117 typedef struct { volatile int counter; } oro_atomic_t;
118 
119 #define ORO_ATOMIC_INIT(i) { (i) }
120 #define ORO_ATOMIC_SETUP oro_atomic_set
121 #define ORO_ATOMIC_CLEANUP(v)
122 
123 #define oro_atomic_read(v) ((v)->counter)
124 #define oro_atomic_set(v,i) (((v)->counter) = (i))
125 
126  static __inline__ void oro_atomic_add(oro_atomic_t *v, int n)
127 {
128  int t;
129 
130  __asm__ __volatile__(
131 "1: lwarx %0,0,%3 # oro_atomic_add\n\
132  add %0,%2,%0\n"
133  PPC405_ERR77(0,%3)
134 " stwcx. %0,0,%3 \n\
135  bne- 1b"
136  : "=&r" (t), "=m" (v->counter)
137  : "r" (a), "r" (&v->counter), "m" (v->counter)
138  : "cc");
139 }
140 
141  static __inline__ int oro_atomic_add_return(oro_atomic_t *v, int n)
142 {
143  int t;
144 
145  __asm__ __volatile__(
147 "1: lwarx %0,0,%2 # oro_atomic_add_return\n\
148  add %0,%1,%0\n"
149  PPC405_ERR77(0,%2)
150 " stwcx. %0,0,%2 \n\
151  bne- 1b"
153  : "=&r" (t)
154  : "r" (a), "r" (&v->counter)
155  : "cc", "memory");
156 
157  return t;
158 }
159 
160 #define oro_atomic_add_negative(a, v) (oro_atomic_add_return((a), (v)) < 0)
161 
162 static __inline__ void oro_atomic_sub(int a, oro_atomic_t *v)
163 {
164  int t;
165 
166  __asm__ __volatile__(
167 "1: lwarx %0,0,%3 # oro_atomic_sub\n\
168  subf %0,%2,%0\n"
169  PPC405_ERR77(0,%3)
170 " stwcx. %0,0,%3 \n\
171  bne- 1b"
172  : "=&r" (t), "=m" (v->counter)
173  : "r" (a), "r" (&v->counter), "m" (v->counter)
174  : "cc");
175 }
176 
177 static __inline__ int oro_atomic_sub_return(oro_atomic_t *v, int n)
178 {
179  int t;
180 
181  __asm__ __volatile__(
183 "1: lwarx %0,0,%2 # oro_atomic_sub_return\n\
184  subf %0,%1,%0\n"
185  PPC405_ERR77(0,%2)
186 " stwcx. %0,0,%2 \n\
187  bne- 1b"
189  : "=&r" (t)
190  : "r" (a), "r" (&v->counter)
191  : "cc", "memory");
192 
193  return t;
194 }
195 
196 static __inline__ void oro_atomic_inc(oro_atomic_t *v)
197 {
198  int t;
199 
200  __asm__ __volatile__(
201 "1: lwarx %0,0,%2 # oro_atomic_inc\n\
202  addic %0,%0,1\n"
203  PPC405_ERR77(0,%2)
204 " stwcx. %0,0,%2 \n\
205  bne- 1b"
206  : "=&r" (t), "=m" (v->counter)
207  : "r" (&v->counter), "m" (v->counter)
208  : "cc");
209 }
210 
211 static __inline__ int oro_atomic_inc_return(oro_atomic_t *v)
212 {
213  int t;
214 
215  __asm__ __volatile__(
217 "1: lwarx %0,0,%1 # oro_atomic_inc_return\n\
218  addic %0,%0,1\n"
219  PPC405_ERR77(0,%1)
220 " stwcx. %0,0,%1 \n\
221  bne- 1b"
223  : "=&r" (t)
224  : "r" (&v->counter)
225  : "cc", "memory");
226 
227  return t;
228 }
229 
230 /*
231  * oro_atomic_inc_and_test - increment and test
232  * @v: pointer of type oro_atomic_t
233  *
234  * Atomically increments @v by 1
235  * and returns true if the result is zero, or false for all
236  * other cases.
237  */
238 #define oro_atomic_inc_and_test(v) (oro_atomic_inc_return(v) == 0)
239 
240 static __inline__ void oro_atomic_dec(oro_atomic_t *v)
241 {
242  int t;
243 
244  __asm__ __volatile__(
245 "1: lwarx %0,0,%2 # oro_atomic_dec\n\
246  addic %0,%0,-1\n"
247  PPC405_ERR77(0,%2)\
248 " stwcx. %0,0,%2\n\
249  bne- 1b"
250  : "=&r" (t), "=m" (v->counter)
251  : "r" (&v->counter), "m" (v->counter)
252  : "cc");
253 }
254 
255 static __inline__ int oro_atomic_dec_return(oro_atomic_t *v)
256 {
257  int t;
258 
259  __asm__ __volatile__(
261 "1: lwarx %0,0,%1 # oro_atomic_dec_return\n\
262  addic %0,%0,-1\n"
263  PPC405_ERR77(0,%1)
264 " stwcx. %0,0,%1\n\
265  bne- 1b"
267  : "=&r" (t)
268  : "r" (&v->counter)
269  : "cc", "memory");
270 
271  return t;
272 }
273 
274 #define oro_atomic_oro_cmpxchg(v, o, n) ((int)oro_cmpxchg(&((v)->counter), (o), (n)))
275 #define oro_atomic_xchg(v, new) (xchg(&((v)->counter), new))
276 
286 #define oro_atomic_add_unless(v, a, u) \
287 ({ \
288  int c, old; \
289  c = oro_atomic_read(v); \
290  for (;;) { \
291  if (unlikely(c == (u))) \
292  break; \
293  old = oro_atomic_oro_cmpxchg((v), c, c + (a)); \
294  if (likely(old == c)) \
295  break; \
296  c = old; \
297  } \
298  c != (u); \
299 })
300 #define oro_atomic_inc_not_zero(v) oro_atomic_add_unless((v), 1, 0)
301 
302 #define oro_atomic_sub_and_test(a, v) (oro_atomic_sub_return((a), (v)) == 0)
303 #define oro_atomic_dec_and_test(v) (oro_atomic_dec_return((v)) == 0)
304 
305 /*
306  * Atomically test *v and decrement if it is greater than 0.
307  * The function returns the old value of *v minus 1.
308  */
309 static __inline__ int oro_atomic_dec_if_positive(oro_atomic_t *v)
310 {
311  int t;
312 
313  __asm__ __volatile__(
315 "1: lwarx %0,0,%1 # oro_atomic_dec_if_positive\n\
316  addic. %0,%0,-1\n\
317  blt- 2f\n"
318  PPC405_ERR77(0,%1)
319 " stwcx. %0,0,%1\n\
320  bne- 1b"
322  "\n\
323 2:" : "=&r" (t)
324  : "r" (&v->counter)
325  : "cc", "memory");
326 
327  return t;
328 }
329 
330 #define smp_mb__before_oro_atomic_dec() smp_mb()
331 #define smp_mb__after_oro_atomic_dec() smp_mb()
332 #define smp_mb__before_oro_atomic_inc() smp_mb()
333 #define smp_mb__after_oro_atomic_inc() smp_mb()
334 
335 #undef ORO_LOCK
336 
337 #ifdef _cplusplus
338 } // end extern "C"
339 #endif // _cplusplus
340 
341 #endif // __ARCH_powerpc_ORO_ATOMIC__
342 
#define LWSYNC_ON_SMP
Definition: oro_atomic.h:63
#define PPC405_ERR77(ra, rb)
Definition: oro_atomic.h:106
volatile int counter
Definition: oro_arch.h:50
void oro_atomic_inc(oro_atomic_t *a)
Increment a atomically.
#define __inline__
Definition: oro_arch.h:52
void oro_atomic_sub(int n, oro_atomic_t *a, int n)
Substract n from a.
#define ISYNC_ON_SMP
Definition: oro_atomic.h:62
struct oro_atomic_t_interface oro_atomic_t
void oro_atomic_dec(oro_atomic_t *a)
Decrement a atomically.
Structure that contains an int for atomic operations.
Definition: oro_arch.h:10
void oro_atomic_add(oro_atomic_t *a, int n)
Add n to a.