Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[pandora-kernel.git] / arch / sh / include / asm / atomic-llsc.h
1 #ifndef __ASM_SH_ATOMIC_LLSC_H
2 #define __ASM_SH_ATOMIC_LLSC_H
3
4 /*
5  * To get proper branch prediction for the main line, we must branch
6  * forward to code at the end of this object's .text section, then
7  * branch back to restart the operation.
8  */
9 static inline void atomic_add(int i, atomic_t *v)
10 {
11         unsigned long tmp;
12
13         __asm__ __volatile__ (
14 "1:     movli.l @%2, %0         ! atomic_add    \n"
15 "       add     %1, %0                          \n"
16 "       movco.l %0, @%2                         \n"
17 "       bf      1b                              \n"
18         : "=&z" (tmp)
19         : "r" (i), "r" (&v->counter)
20         : "t");
21 }
22
23 static inline void atomic_sub(int i, atomic_t *v)
24 {
25         unsigned long tmp;
26
27         __asm__ __volatile__ (
28 "1:     movli.l @%2, %0         ! atomic_sub    \n"
29 "       sub     %1, %0                          \n"
30 "       movco.l %0, @%2                         \n"
31 "       bf      1b                              \n"
32         : "=&z" (tmp)
33         : "r" (i), "r" (&v->counter)
34         : "t");
35 }
36
37 /*
38  * SH-4A note:
39  *
40  * We basically get atomic_xxx_return() for free compared with
41  * atomic_xxx(). movli.l/movco.l require r0 due to the instruction
42  * encoding, so the retval is automatically set without having to
43  * do any special work.
44  */
45 static inline int atomic_add_return(int i, atomic_t *v)
46 {
47         unsigned long temp;
48
49         __asm__ __volatile__ (
50 "1:     movli.l @%2, %0         ! atomic_add_return     \n"
51 "       add     %1, %0                                  \n"
52 "       movco.l %0, @%2                                 \n"
53 "       bf      1b                                      \n"
54 "       synco                                           \n"
55         : "=&z" (temp)
56         : "r" (i), "r" (&v->counter)
57         : "t");
58
59         return temp;
60 }
61
62 static inline int atomic_sub_return(int i, atomic_t *v)
63 {
64         unsigned long temp;
65
66         __asm__ __volatile__ (
67 "1:     movli.l @%2, %0         ! atomic_sub_return     \n"
68 "       sub     %1, %0                                  \n"
69 "       movco.l %0, @%2                                 \n"
70 "       bf      1b                                      \n"
71 "       synco                                           \n"
72         : "=&z" (temp)
73         : "r" (i), "r" (&v->counter)
74         : "t");
75
76         return temp;
77 }
78
79 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
80 {
81         unsigned long tmp;
82
83         __asm__ __volatile__ (
84 "1:     movli.l @%2, %0         ! atomic_clear_mask     \n"
85 "       and     %1, %0                                  \n"
86 "       movco.l %0, @%2                                 \n"
87 "       bf      1b                                      \n"
88         : "=&z" (tmp)
89         : "r" (~mask), "r" (&v->counter)
90         : "t");
91 }
92
93 static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
94 {
95         unsigned long tmp;
96
97         __asm__ __volatile__ (
98 "1:     movli.l @%2, %0         ! atomic_set_mask       \n"
99 "       or      %1, %0                                  \n"
100 "       movco.l %0, @%2                                 \n"
101 "       bf      1b                                      \n"
102         : "=&z" (tmp)
103         : "r" (mask), "r" (&v->counter)
104         : "t");
105 }
106
107 #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
108
109 /**
110  * atomic_add_unless - add unless the number is a given value
111  * @v: pointer of type atomic_t
112  * @a: the amount to add to v...
113  * @u: ...unless v is equal to u.
114  *
115  * Atomically adds @a to @v, so long as it was not @u.
116  * Returns non-zero if @v was not @u, and zero otherwise.
117  */
118 static inline int atomic_add_unless(atomic_t *v, int a, int u)
119 {
120         int c, old;
121         c = atomic_read(v);
122         for (;;) {
123                 if (unlikely(c == (u)))
124                         break;
125                 old = atomic_cmpxchg((v), c, c + (a));
126                 if (likely(old == c))
127                         break;
128                 c = old;
129         }
130
131         return c != (u);
132 }
133
134 #endif /* __ASM_SH_ATOMIC_LLSC_H */