fc46b664c49e8adfb58bd4c45fe9f439ee7eb96a
[sfrench/cifs-2.6.git] / arch / powerpc / include / asm / cmpxchg.h
1 #ifndef _ASM_POWERPC_CMPXCHG_H_
2 #define _ASM_POWERPC_CMPXCHG_H_
3
4 #ifdef __KERNEL__
5 #include <linux/compiler.h>
6 #include <asm/synch.h>
7 #include <asm/asm-compat.h>
8 #include <linux/bug.h>
9
10 #ifdef __BIG_ENDIAN
11 #define BITOFF_CAL(size, off)   ((sizeof(u32) - size - off) * BITS_PER_BYTE)
12 #else
13 #define BITOFF_CAL(size, off)   (off * BITS_PER_BYTE)
14 #endif
15
16 #define XCHG_GEN(type, sfx, cl)                         \
17 static inline u32 __xchg_##type##sfx(volatile void *p, u32 val) \
18 {                                                               \
19         unsigned int prev, prev_mask, tmp, bitoff, off;         \
20                                                                 \
21         off = (unsigned long)p % sizeof(u32);                   \
22         bitoff = BITOFF_CAL(sizeof(type), off);                 \
23         p -= off;                                               \
24         val <<= bitoff;                                         \
25         prev_mask = (u32)(type)-1 << bitoff;                    \
26                                                                 \
27         __asm__ __volatile__(                                   \
28 "1:     lwarx   %0,0,%3\n"                                      \
29 "       andc    %1,%0,%5\n"                                     \
30 "       or      %1,%1,%4\n"                                     \
31         PPC405_ERR77(0,%3)                                      \
32 "       stwcx.  %1,0,%3\n"                                      \
33 "       bne-    1b\n"                                           \
34         : "=&r" (prev), "=&r" (tmp), "+m" (*(u32*)p)            \
35         : "r" (p), "r" (val), "r" (prev_mask)                   \
36         : "cc", cl);                                            \
37                                                                 \
38         return prev >> bitoff;                                  \
39 }
40
41 #define CMPXCHG_GEN(type, sfx, br, br2, cl)                     \
42 static inline                                                   \
43 u32 __cmpxchg_##type##sfx(volatile void *p, u32 old, u32 new)   \
44 {                                                               \
45         unsigned int prev, prev_mask, tmp, bitoff, off;         \
46                                                                 \
47         off = (unsigned long)p % sizeof(u32);                   \
48         bitoff = BITOFF_CAL(sizeof(type), off);                 \
49         p -= off;                                               \
50         old <<= bitoff;                                         \
51         new <<= bitoff;                                         \
52         prev_mask = (u32)(type)-1 << bitoff;                    \
53                                                                 \
54         __asm__ __volatile__(                                   \
55         br                                                      \
56 "1:     lwarx   %0,0,%3\n"                                      \
57 "       and     %1,%0,%6\n"                                     \
58 "       cmpw    0,%1,%4\n"                                      \
59 "       bne-    2f\n"                                           \
60 "       andc    %1,%0,%6\n"                                     \
61 "       or      %1,%1,%5\n"                                     \
62         PPC405_ERR77(0,%3)                                      \
63 "       stwcx.  %1,0,%3\n"                                      \
64 "       bne-    1b\n"                                           \
65         br2                                                     \
66         "\n"                                                    \
67 "2:"                                                            \
68         : "=&r" (prev), "=&r" (tmp), "+m" (*(u32*)p)            \
69         : "r" (p), "r" (old), "r" (new), "r" (prev_mask)        \
70         : "cc", cl);                                            \
71                                                                 \
72         return prev >> bitoff;                                  \
73 }
74
75 /*
76  * Atomic exchange
77  *
78  * Changes the memory location '*p' to be val and returns
79  * the previous value stored there.
80  */
81
82 XCHG_GEN(u8, _local, "memory");
83 XCHG_GEN(u8, _relaxed, "cc");
84 XCHG_GEN(u16, _local, "memory");
85 XCHG_GEN(u16, _relaxed, "cc");
86
87 static __always_inline unsigned long
88 __xchg_u32_local(volatile void *p, unsigned long val)
89 {
90         unsigned long prev;
91
92         __asm__ __volatile__(
93 "1:     lwarx   %0,0,%2 \n"
94         PPC405_ERR77(0,%2)
95 "       stwcx.  %3,0,%2 \n\
96         bne-    1b"
97         : "=&r" (prev), "+m" (*(volatile unsigned int *)p)
98         : "r" (p), "r" (val)
99         : "cc", "memory");
100
101         return prev;
102 }
103
104 static __always_inline unsigned long
105 __xchg_u32_relaxed(u32 *p, unsigned long val)
106 {
107         unsigned long prev;
108
109         __asm__ __volatile__(
110 "1:     lwarx   %0,0,%2\n"
111         PPC405_ERR77(0, %2)
112 "       stwcx.  %3,0,%2\n"
113 "       bne-    1b"
114         : "=&r" (prev), "+m" (*p)
115         : "r" (p), "r" (val)
116         : "cc");
117
118         return prev;
119 }
120
121 #ifdef CONFIG_PPC64
122 static __always_inline unsigned long
123 __xchg_u64_local(volatile void *p, unsigned long val)
124 {
125         unsigned long prev;
126
127         __asm__ __volatile__(
128 "1:     ldarx   %0,0,%2 \n"
129         PPC405_ERR77(0,%2)
130 "       stdcx.  %3,0,%2 \n\
131         bne-    1b"
132         : "=&r" (prev), "+m" (*(volatile unsigned long *)p)
133         : "r" (p), "r" (val)
134         : "cc", "memory");
135
136         return prev;
137 }
138
139 static __always_inline unsigned long
140 __xchg_u64_relaxed(u64 *p, unsigned long val)
141 {
142         unsigned long prev;
143
144         __asm__ __volatile__(
145 "1:     ldarx   %0,0,%2\n"
146         PPC405_ERR77(0, %2)
147 "       stdcx.  %3,0,%2\n"
148 "       bne-    1b"
149         : "=&r" (prev), "+m" (*p)
150         : "r" (p), "r" (val)
151         : "cc");
152
153         return prev;
154 }
155 #endif
156
157 static __always_inline unsigned long
158 __xchg_local(void *ptr, unsigned long x, unsigned int size)
159 {
160         switch (size) {
161         case 1:
162                 return __xchg_u8_local(ptr, x);
163         case 2:
164                 return __xchg_u16_local(ptr, x);
165         case 4:
166                 return __xchg_u32_local(ptr, x);
167 #ifdef CONFIG_PPC64
168         case 8:
169                 return __xchg_u64_local(ptr, x);
170 #endif
171         }
172         BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg");
173         return x;
174 }
175
176 static __always_inline unsigned long
177 __xchg_relaxed(void *ptr, unsigned long x, unsigned int size)
178 {
179         switch (size) {
180         case 1:
181                 return __xchg_u8_relaxed(ptr, x);
182         case 2:
183                 return __xchg_u16_relaxed(ptr, x);
184         case 4:
185                 return __xchg_u32_relaxed(ptr, x);
186 #ifdef CONFIG_PPC64
187         case 8:
188                 return __xchg_u64_relaxed(ptr, x);
189 #endif
190         }
191         BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg_local");
192         return x;
193 }
194 #define xchg_local(ptr,x)                                                    \
195   ({                                                                         \
196      __typeof__(*(ptr)) _x_ = (x);                                           \
197      (__typeof__(*(ptr))) __xchg_local((ptr),                                \
198                 (unsigned long)_x_, sizeof(*(ptr)));                         \
199   })
200
201 #define xchg_relaxed(ptr, x)                                            \
202 ({                                                                      \
203         __typeof__(*(ptr)) _x_ = (x);                                   \
204         (__typeof__(*(ptr))) __xchg_relaxed((ptr),                      \
205                         (unsigned long)_x_, sizeof(*(ptr)));            \
206 })
207 /*
208  * Compare and exchange - if *p == old, set it to new,
209  * and return the old value of *p.
210  */
211
212 CMPXCHG_GEN(u8, , PPC_ATOMIC_ENTRY_BARRIER, PPC_ATOMIC_EXIT_BARRIER, "memory");
213 CMPXCHG_GEN(u8, _local, , , "memory");
214 CMPXCHG_GEN(u8, _acquire, , PPC_ACQUIRE_BARRIER, "memory");
215 CMPXCHG_GEN(u8, _relaxed, , , "cc");
216 CMPXCHG_GEN(u16, , PPC_ATOMIC_ENTRY_BARRIER, PPC_ATOMIC_EXIT_BARRIER, "memory");
217 CMPXCHG_GEN(u16, _local, , , "memory");
218 CMPXCHG_GEN(u16, _acquire, , PPC_ACQUIRE_BARRIER, "memory");
219 CMPXCHG_GEN(u16, _relaxed, , , "cc");
220
221 static __always_inline unsigned long
222 __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
223 {
224         unsigned int prev;
225
226         __asm__ __volatile__ (
227         PPC_ATOMIC_ENTRY_BARRIER
228 "1:     lwarx   %0,0,%2         # __cmpxchg_u32\n\
229         cmpw    0,%0,%3\n\
230         bne-    2f\n"
231         PPC405_ERR77(0,%2)
232 "       stwcx.  %4,0,%2\n\
233         bne-    1b"
234         PPC_ATOMIC_EXIT_BARRIER
235         "\n\
236 2:"
237         : "=&r" (prev), "+m" (*p)
238         : "r" (p), "r" (old), "r" (new)
239         : "cc", "memory");
240
241         return prev;
242 }
243
244 static __always_inline unsigned long
245 __cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
246                         unsigned long new)
247 {
248         unsigned int prev;
249
250         __asm__ __volatile__ (
251 "1:     lwarx   %0,0,%2         # __cmpxchg_u32\n\
252         cmpw    0,%0,%3\n\
253         bne-    2f\n"
254         PPC405_ERR77(0,%2)
255 "       stwcx.  %4,0,%2\n\
256         bne-    1b"
257         "\n\
258 2:"
259         : "=&r" (prev), "+m" (*p)
260         : "r" (p), "r" (old), "r" (new)
261         : "cc", "memory");
262
263         return prev;
264 }
265
266 static __always_inline unsigned long
267 __cmpxchg_u32_relaxed(u32 *p, unsigned long old, unsigned long new)
268 {
269         unsigned long prev;
270
271         __asm__ __volatile__ (
272 "1:     lwarx   %0,0,%2         # __cmpxchg_u32_relaxed\n"
273 "       cmpw    0,%0,%3\n"
274 "       bne-    2f\n"
275         PPC405_ERR77(0, %2)
276 "       stwcx.  %4,0,%2\n"
277 "       bne-    1b\n"
278 "2:"
279         : "=&r" (prev), "+m" (*p)
280         : "r" (p), "r" (old), "r" (new)
281         : "cc");
282
283         return prev;
284 }
285
286 /*
287  * cmpxchg family don't have order guarantee if cmp part fails, therefore we
288  * can avoid superfluous barriers if we use assembly code to implement
289  * cmpxchg() and cmpxchg_acquire(), however we don't do the similar for
290  * cmpxchg_release() because that will result in putting a barrier in the
291  * middle of a ll/sc loop, which is probably a bad idea. For example, this
292  * might cause the conditional store more likely to fail.
293  */
294 static __always_inline unsigned long
295 __cmpxchg_u32_acquire(u32 *p, unsigned long old, unsigned long new)
296 {
297         unsigned long prev;
298
299         __asm__ __volatile__ (
300 "1:     lwarx   %0,0,%2         # __cmpxchg_u32_acquire\n"
301 "       cmpw    0,%0,%3\n"
302 "       bne-    2f\n"
303         PPC405_ERR77(0, %2)
304 "       stwcx.  %4,0,%2\n"
305 "       bne-    1b\n"
306         PPC_ACQUIRE_BARRIER
307         "\n"
308 "2:"
309         : "=&r" (prev), "+m" (*p)
310         : "r" (p), "r" (old), "r" (new)
311         : "cc", "memory");
312
313         return prev;
314 }
315
316 #ifdef CONFIG_PPC64
317 static __always_inline unsigned long
318 __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
319 {
320         unsigned long prev;
321
322         __asm__ __volatile__ (
323         PPC_ATOMIC_ENTRY_BARRIER
324 "1:     ldarx   %0,0,%2         # __cmpxchg_u64\n\
325         cmpd    0,%0,%3\n\
326         bne-    2f\n\
327         stdcx.  %4,0,%2\n\
328         bne-    1b"
329         PPC_ATOMIC_EXIT_BARRIER
330         "\n\
331 2:"
332         : "=&r" (prev), "+m" (*p)
333         : "r" (p), "r" (old), "r" (new)
334         : "cc", "memory");
335
336         return prev;
337 }
338
339 static __always_inline unsigned long
340 __cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
341                         unsigned long new)
342 {
343         unsigned long prev;
344
345         __asm__ __volatile__ (
346 "1:     ldarx   %0,0,%2         # __cmpxchg_u64\n\
347         cmpd    0,%0,%3\n\
348         bne-    2f\n\
349         stdcx.  %4,0,%2\n\
350         bne-    1b"
351         "\n\
352 2:"
353         : "=&r" (prev), "+m" (*p)
354         : "r" (p), "r" (old), "r" (new)
355         : "cc", "memory");
356
357         return prev;
358 }
359
360 static __always_inline unsigned long
361 __cmpxchg_u64_relaxed(u64 *p, unsigned long old, unsigned long new)
362 {
363         unsigned long prev;
364
365         __asm__ __volatile__ (
366 "1:     ldarx   %0,0,%2         # __cmpxchg_u64_relaxed\n"
367 "       cmpd    0,%0,%3\n"
368 "       bne-    2f\n"
369 "       stdcx.  %4,0,%2\n"
370 "       bne-    1b\n"
371 "2:"
372         : "=&r" (prev), "+m" (*p)
373         : "r" (p), "r" (old), "r" (new)
374         : "cc");
375
376         return prev;
377 }
378
379 static __always_inline unsigned long
380 __cmpxchg_u64_acquire(u64 *p, unsigned long old, unsigned long new)
381 {
382         unsigned long prev;
383
384         __asm__ __volatile__ (
385 "1:     ldarx   %0,0,%2         # __cmpxchg_u64_acquire\n"
386 "       cmpd    0,%0,%3\n"
387 "       bne-    2f\n"
388 "       stdcx.  %4,0,%2\n"
389 "       bne-    1b\n"
390         PPC_ACQUIRE_BARRIER
391         "\n"
392 "2:"
393         : "=&r" (prev), "+m" (*p)
394         : "r" (p), "r" (old), "r" (new)
395         : "cc", "memory");
396
397         return prev;
398 }
399 #endif
400
401 static __always_inline unsigned long
402 __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
403           unsigned int size)
404 {
405         switch (size) {
406         case 1:
407                 return __cmpxchg_u8(ptr, old, new);
408         case 2:
409                 return __cmpxchg_u16(ptr, old, new);
410         case 4:
411                 return __cmpxchg_u32(ptr, old, new);
412 #ifdef CONFIG_PPC64
413         case 8:
414                 return __cmpxchg_u64(ptr, old, new);
415 #endif
416         }
417         BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg");
418         return old;
419 }
420
421 static __always_inline unsigned long
422 __cmpxchg_local(void *ptr, unsigned long old, unsigned long new,
423           unsigned int size)
424 {
425         switch (size) {
426         case 1:
427                 return __cmpxchg_u8_local(ptr, old, new);
428         case 2:
429                 return __cmpxchg_u16_local(ptr, old, new);
430         case 4:
431                 return __cmpxchg_u32_local(ptr, old, new);
432 #ifdef CONFIG_PPC64
433         case 8:
434                 return __cmpxchg_u64_local(ptr, old, new);
435 #endif
436         }
437         BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_local");
438         return old;
439 }
440
441 static __always_inline unsigned long
442 __cmpxchg_relaxed(void *ptr, unsigned long old, unsigned long new,
443                   unsigned int size)
444 {
445         switch (size) {
446         case 1:
447                 return __cmpxchg_u8_relaxed(ptr, old, new);
448         case 2:
449                 return __cmpxchg_u16_relaxed(ptr, old, new);
450         case 4:
451                 return __cmpxchg_u32_relaxed(ptr, old, new);
452 #ifdef CONFIG_PPC64
453         case 8:
454                 return __cmpxchg_u64_relaxed(ptr, old, new);
455 #endif
456         }
457         BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_relaxed");
458         return old;
459 }
460
461 static __always_inline unsigned long
462 __cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
463                   unsigned int size)
464 {
465         switch (size) {
466         case 1:
467                 return __cmpxchg_u8_acquire(ptr, old, new);
468         case 2:
469                 return __cmpxchg_u16_acquire(ptr, old, new);
470         case 4:
471                 return __cmpxchg_u32_acquire(ptr, old, new);
472 #ifdef CONFIG_PPC64
473         case 8:
474                 return __cmpxchg_u64_acquire(ptr, old, new);
475 #endif
476         }
477         BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_acquire");
478         return old;
479 }
480 #define cmpxchg(ptr, o, n)                                               \
481   ({                                                                     \
482      __typeof__(*(ptr)) _o_ = (o);                                       \
483      __typeof__(*(ptr)) _n_ = (n);                                       \
484      (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_,           \
485                                     (unsigned long)_n_, sizeof(*(ptr))); \
486   })
487
488
489 #define cmpxchg_local(ptr, o, n)                                         \
490   ({                                                                     \
491      __typeof__(*(ptr)) _o_ = (o);                                       \
492      __typeof__(*(ptr)) _n_ = (n);                                       \
493      (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_,     \
494                                     (unsigned long)_n_, sizeof(*(ptr))); \
495   })
496
497 #define cmpxchg_relaxed(ptr, o, n)                                      \
498 ({                                                                      \
499         __typeof__(*(ptr)) _o_ = (o);                                   \
500         __typeof__(*(ptr)) _n_ = (n);                                   \
501         (__typeof__(*(ptr))) __cmpxchg_relaxed((ptr),                   \
502                         (unsigned long)_o_, (unsigned long)_n_,         \
503                         sizeof(*(ptr)));                                \
504 })
505
506 #define cmpxchg_acquire(ptr, o, n)                                      \
507 ({                                                                      \
508         __typeof__(*(ptr)) _o_ = (o);                                   \
509         __typeof__(*(ptr)) _n_ = (n);                                   \
510         (__typeof__(*(ptr))) __cmpxchg_acquire((ptr),                   \
511                         (unsigned long)_o_, (unsigned long)_n_,         \
512                         sizeof(*(ptr)));                                \
513 })
514 #ifdef CONFIG_PPC64
515 #define cmpxchg64(ptr, o, n)                                            \
516   ({                                                                    \
517         BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
518         cmpxchg((ptr), (o), (n));                                       \
519   })
520 #define cmpxchg64_local(ptr, o, n)                                      \
521   ({                                                                    \
522         BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
523         cmpxchg_local((ptr), (o), (n));                                 \
524   })
525 #define cmpxchg64_relaxed(ptr, o, n)                                    \
526 ({                                                                      \
527         BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
528         cmpxchg_relaxed((ptr), (o), (n));                               \
529 })
530 #define cmpxchg64_acquire(ptr, o, n)                                    \
531 ({                                                                      \
532         BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
533         cmpxchg_acquire((ptr), (o), (n));                               \
534 })
535 #else
536 #include <asm-generic/cmpxchg-local.h>
537 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
538 #endif
539
540 #endif /* __KERNEL__ */
541 #endif /* _ASM_POWERPC_CMPXCHG_H_ */