Merge tag 'spi-v4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi
[sfrench/cifs-2.6.git] / arch / frv / include / asm / atomic_defs.h
1
2 #include <asm/spr-regs.h>
3
4 #ifdef __ATOMIC_LIB__
5
6 #ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
7
8 #define ATOMIC_QUALS
9 #define ATOMIC_EXPORT(x)        EXPORT_SYMBOL(x)
10
11 #else /* !OUTOFLINE && LIB */
12
13 #define ATOMIC_OP_RETURN(op)
14 #define ATOMIC_FETCH_OP(op)
15
16 #endif /* OUTOFLINE */
17
18 #else /* !__ATOMIC_LIB__ */
19
20 #define ATOMIC_EXPORT(x)
21
22 #ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS
23
24 #define ATOMIC_OP_RETURN(op)                                            \
25 extern int __atomic_##op##_return(int i, int *v);                       \
26 extern long long __atomic64_##op##_return(long long i, long long *v);
27
28 #define ATOMIC_FETCH_OP(op)                                             \
29 extern int __atomic32_fetch_##op(int i, int *v);                        \
30 extern long long __atomic64_fetch_##op(long long i, long long *v);
31
32 #else /* !OUTOFLINE && !LIB */
33
34 #define ATOMIC_QUALS    static inline
35
36 #endif /* OUTOFLINE */
37 #endif /* __ATOMIC_LIB__ */
38
39
40 /*
41  * Note on the 64 bit inline asm variants...
42  *
43  * CSTD is a conditional instruction and needs a constrained memory reference.
44  * Normally 'U' provides the correct constraints for conditional instructions
45  * and this is used for the 32 bit version, however 'U' does not appear to work
46  * for 64 bit values (gcc-4.9)
47  *
48  * The exact constraint is that conditional instructions cannot deal with an
49  * immediate displacement in the memory reference, so what we do is we read the
50  * address through a volatile cast into a local variable in order to insure we
51  * _have_ to compute the correct address without displacement. This allows us
52  * to use the regular 'm' for the memory address.
53  *
54  * Furthermore, the %Ln operand, which prints the low word register (r+1),
55  * really only works for registers, this means we cannot allow immediate values
56  * for the 64 bit versions -- like we do for the 32 bit ones.
57  *
58  */
59
60 #ifndef ATOMIC_OP_RETURN
61 #define ATOMIC_OP_RETURN(op)                                            \
62 ATOMIC_QUALS int __atomic_##op##_return(int i, int *v)                  \
63 {                                                                       \
64         int val;                                                        \
65                                                                         \
66         asm volatile(                                                   \
67             "0:                                         \n"             \
68             "   orcc            gr0,gr0,gr0,icc3        \n"             \
69             "   ckeq            icc3,cc7                \n"             \
70             "   ld.p            %M0,%1                  \n"             \
71             "   orcr            cc7,cc7,cc3             \n"             \
72             "   "#op"%I2        %1,%2,%1                \n"             \
73             "   cst.p           %1,%M0          ,cc3,#1 \n"             \
74             "   corcc           gr29,gr29,gr0   ,cc3,#1 \n"             \
75             "   beq             icc3,#0,0b              \n"             \
76             : "+U"(*v), "=&r"(val)                                      \
77             : "NPr"(i)                                                  \
78             : "memory", "cc7", "cc3", "icc3"                            \
79             );                                                          \
80                                                                         \
81         return val;                                                     \
82 }                                                                       \
83 ATOMIC_EXPORT(__atomic_##op##_return);                                  \
84                                                                         \
85 ATOMIC_QUALS long long __atomic64_##op##_return(long long i, long long *v)      \
86 {                                                                       \
87         long long *__v = READ_ONCE(v);                                  \
88         long long val;                                                  \
89                                                                         \
90         asm volatile(                                                   \
91             "0:                                         \n"             \
92             "   orcc            gr0,gr0,gr0,icc3        \n"             \
93             "   ckeq            icc3,cc7                \n"             \
94             "   ldd.p           %M0,%1                  \n"             \
95             "   orcr            cc7,cc7,cc3             \n"             \
96             "   "#op"cc         %L1,%L2,%L1,icc0        \n"             \
97             "   "#op"x          %1,%2,%1,icc0           \n"             \
98             "   cstd.p          %1,%M0          ,cc3,#1 \n"             \
99             "   corcc           gr29,gr29,gr0   ,cc3,#1 \n"             \
100             "   beq             icc3,#0,0b              \n"             \
101             : "+m"(*__v), "=&e"(val)                                    \
102             : "e"(i)                                                    \
103             : "memory", "cc7", "cc3", "icc0", "icc3"                    \
104             );                                                          \
105                                                                         \
106         return val;                                                     \
107 }                                                                       \
108 ATOMIC_EXPORT(__atomic64_##op##_return);
109 #endif
110
111 #ifndef ATOMIC_FETCH_OP
112 #define ATOMIC_FETCH_OP(op)                                             \
113 ATOMIC_QUALS int __atomic32_fetch_##op(int i, int *v)                   \
114 {                                                                       \
115         int old, tmp;                                                   \
116                                                                         \
117         asm volatile(                                                   \
118                 "0:                                             \n"     \
119                 "       orcc            gr0,gr0,gr0,icc3        \n"     \
120                 "       ckeq            icc3,cc7                \n"     \
121                 "       ld.p            %M0,%1                  \n"     \
122                 "       orcr            cc7,cc7,cc3             \n"     \
123                 "       "#op"%I3        %1,%3,%2                \n"     \
124                 "       cst.p           %2,%M0          ,cc3,#1 \n"     \
125                 "       corcc           gr29,gr29,gr0   ,cc3,#1 \n"     \
126                 "       beq             icc3,#0,0b              \n"     \
127                 : "+U"(*v), "=&r"(old), "=r"(tmp)                       \
128                 : "NPr"(i)                                              \
129                 : "memory", "cc7", "cc3", "icc3"                        \
130                 );                                                      \
131                                                                         \
132         return old;                                                     \
133 }                                                                       \
134 ATOMIC_EXPORT(__atomic32_fetch_##op);                                   \
135                                                                         \
136 ATOMIC_QUALS long long __atomic64_fetch_##op(long long i, long long *v) \
137 {                                                                       \
138         long long *__v = READ_ONCE(v);                                  \
139         long long old, tmp;                                             \
140                                                                         \
141         asm volatile(                                                   \
142                 "0:                                             \n"     \
143                 "       orcc            gr0,gr0,gr0,icc3        \n"     \
144                 "       ckeq            icc3,cc7                \n"     \
145                 "       ldd.p           %M0,%1                  \n"     \
146                 "       orcr            cc7,cc7,cc3             \n"     \
147                 "       "#op"           %L1,%L3,%L2             \n"     \
148                 "       "#op"           %1,%3,%2                \n"     \
149                 "       cstd.p          %2,%M0          ,cc3,#1 \n"     \
150                 "       corcc           gr29,gr29,gr0   ,cc3,#1 \n"     \
151                 "       beq             icc3,#0,0b              \n"     \
152                 : "+m"(*__v), "=&e"(old), "=e"(tmp)                     \
153                 : "e"(i)                                                \
154                 : "memory", "cc7", "cc3", "icc3"                        \
155                 );                                                      \
156                                                                         \
157         return old;                                                     \
158 }                                                                       \
159 ATOMIC_EXPORT(__atomic64_fetch_##op);
160 #endif
161
162 ATOMIC_FETCH_OP(or)
163 ATOMIC_FETCH_OP(and)
164 ATOMIC_FETCH_OP(xor)
165 ATOMIC_FETCH_OP(add)
166 ATOMIC_FETCH_OP(sub)
167
168 ATOMIC_OP_RETURN(add)
169 ATOMIC_OP_RETURN(sub)
170
171 #undef ATOMIC_FETCH_OP
172 #undef ATOMIC_OP_RETURN
173 #undef ATOMIC_QUALS
174 #undef ATOMIC_EXPORT