aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/include
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2013-09-16 10:22:05 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2013-10-24 11:16:52 -0400
commit370b0b5f7744d62a9ba6c25fd6b0dcba84419443 (patch)
tree110ea22f87f28cf95f11e83e5312169f62e29b0d /arch/s390/include
parent9a70a42835d2be9bd1862d839f2debaaea79ba32 (diff)
s390/bitops: remove CONFIG_SMP / simplify non-atomic bitops
Remove CONFIG_SMP from bitops code. This reduces the C code significantly but also generates better code for the SMP case. This means that for !CONFIG_SMP set_bit() and friends now also have compare and swap semantics (read: more code). However nobody really cares for !CONFIG_SMP and this is the trade-off to simplify the SMP code which we do care about. The non-atomic bitops like __set_bit() now generate also better code because the old code did not have a __builtin_contant_p() check for the CONFIG_SMP case and therefore always generated the inline assembly variant. However the inline assemblies for the non-atomic case now got completely removed since gcc can produce better code, which accesses less memory operands. test_bit() got also a bit simplified since it did have a __builtin_constant_p() check, however two identical code pathes for each case (written differently). In result this mainly reduces the to be maintained code but is not very relevant for code generation, since there are not many non-atomic bitops usages that we care about. (code reduction defconfig kernel image before/after: 560 bytes). Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/include')
-rw-r--r--arch/s390/include/asm/bitops.h276
1 files changed, 65 insertions, 211 deletions
diff --git a/arch/s390/include/asm/bitops.h b/arch/s390/include/asm/bitops.h
index bb26481a723f..6038349c8410 100644
--- a/arch/s390/include/asm/bitops.h
+++ b/arch/s390/include/asm/bitops.h
@@ -15,6 +15,7 @@
15#error only <linux/bitops.h> can be included directly 15#error only <linux/bitops.h> can be included directly
16#endif 16#endif
17 17
18#include <linux/typecheck.h>
18#include <linux/compiler.h> 19#include <linux/compiler.h>
19 20
20/* 21/*
@@ -54,8 +55,6 @@
54 */ 55 */
55 56
56/* bitmap tables from arch/s390/kernel/bitmap.c */ 57/* bitmap tables from arch/s390/kernel/bitmap.c */
57extern const char _oi_bitmap[];
58extern const char _ni_bitmap[];
59extern const char _zb_findmap[]; 58extern const char _zb_findmap[];
60extern const char _sb_findmap[]; 59extern const char _sb_findmap[];
61 60
@@ -69,15 +68,15 @@ extern const char _sb_findmap[];
69({ \ 68({ \
70 unsigned long __old, __new; \ 69 unsigned long __old, __new; \
71 \ 70 \
71 typecheck(unsigned long *, (__addr)); \
72 asm volatile( \ 72 asm volatile( \
73 " l %0,%2\n" \ 73 " l %0,%2\n" \
74 "0: lr %1,%0\n" \ 74 "0: lr %1,%0\n" \
75 __op_string " %1,%3\n" \ 75 __op_string " %1,%3\n" \
76 " cs %0,%1,%2\n" \ 76 " cs %0,%1,%2\n" \
77 " jl 0b" \ 77 " jl 0b" \
78 : "=&d" (__old), "=&d" (__new), \ 78 : "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\
79 "=Q" (*(unsigned long *) __addr) \ 79 : "d" (__val) \
80 : "d" (__val), "Q" (*(unsigned long *) __addr) \
81 : "cc"); \ 80 : "cc"); \
82 __old; \ 81 __old; \
83}) 82})
@@ -94,9 +93,10 @@ extern const char _sb_findmap[];
94({ \ 93({ \
95 unsigned long __old; \ 94 unsigned long __old; \
96 \ 95 \
96 typecheck(unsigned long *, (__addr)); \
97 asm volatile( \ 97 asm volatile( \
98 __op_string " %0,%2,%1\n" \ 98 __op_string " %0,%2,%1\n" \
99 : "=d" (__old), "+Q" (*(unsigned long *)__addr) \ 99 : "=d" (__old), "+Q" (*(__addr)) \
100 : "d" (__val) \ 100 : "d" (__val) \
101 : "cc"); \ 101 : "cc"); \
102 __old; \ 102 __old; \
@@ -112,15 +112,15 @@ extern const char _sb_findmap[];
112({ \ 112({ \
113 unsigned long __old, __new; \ 113 unsigned long __old, __new; \
114 \ 114 \
115 typecheck(unsigned long *, (__addr)); \
115 asm volatile( \ 116 asm volatile( \
116 " lg %0,%2\n" \ 117 " lg %0,%2\n" \
117 "0: lgr %1,%0\n" \ 118 "0: lgr %1,%0\n" \
118 __op_string " %1,%3\n" \ 119 __op_string " %1,%3\n" \
119 " csg %0,%1,%2\n" \ 120 " csg %0,%1,%2\n" \
120 " jl 0b" \ 121 " jl 0b" \
121 : "=&d" (__old), "=&d" (__new), \ 122 : "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\
122 "=Q" (*(unsigned long *) __addr) \ 123 : "d" (__val) \
123 : "d" (__val), "Q" (*(unsigned long *) __addr) \
124 : "cc"); \ 124 : "cc"); \
125 __old; \ 125 __old; \
126}) 126})
@@ -131,294 +131,148 @@ extern const char _sb_findmap[];
131 131
132#define __BITOPS_WORDS(bits) (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG) 132#define __BITOPS_WORDS(bits) (((bits) + BITS_PER_LONG - 1) / BITS_PER_LONG)
133 133
134#ifdef CONFIG_SMP 134static inline unsigned long *
135/* 135__bitops_word(unsigned long nr, volatile unsigned long *ptr)
136 * SMP safe set_bit routine based on compare and swap (CS) 136{
137 */ 137 unsigned long addr;
138static inline void set_bit_cs(unsigned long nr, volatile unsigned long *ptr) 138
139 addr = (unsigned long)ptr + ((nr ^ (nr & (BITS_PER_LONG - 1))) >> 3);
140 return (unsigned long *)addr;
141}
142
143static inline unsigned char *
144__bitops_byte(unsigned long nr, volatile unsigned long *ptr)
145{
146 return ((unsigned char *)ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
147}
148
149static inline void set_bit(unsigned long nr, volatile unsigned long *ptr)
139{ 150{
140 unsigned long addr, mask; 151 unsigned long *addr = __bitops_word(nr, ptr);
152 unsigned long mask;
141 153
142 addr = (unsigned long) ptr;
143 /* calculate address for CS */
144 addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
145 /* make OR mask */
146 mask = 1UL << (nr & (BITS_PER_LONG - 1)); 154 mask = 1UL << (nr & (BITS_PER_LONG - 1));
147 /* Do the atomic update. */
148 __BITOPS_LOOP(addr, mask, __BITOPS_OR); 155 __BITOPS_LOOP(addr, mask, __BITOPS_OR);
149} 156}
150 157
151/* 158static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
152 * SMP safe clear_bit routine based on compare and swap (CS)
153 */
154static inline void clear_bit_cs(unsigned long nr, volatile unsigned long *ptr)
155{ 159{
156 unsigned long addr, mask; 160 unsigned long *addr = __bitops_word(nr, ptr);
161 unsigned long mask;
157 162
158 addr = (unsigned long) ptr;
159 /* calculate address for CS */
160 addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
161 /* make AND mask */
162 mask = ~(1UL << (nr & (BITS_PER_LONG - 1))); 163 mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
163 /* Do the atomic update. */
164 __BITOPS_LOOP(addr, mask, __BITOPS_AND); 164 __BITOPS_LOOP(addr, mask, __BITOPS_AND);
165} 165}
166 166
167/* 167static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
168 * SMP safe change_bit routine based on compare and swap (CS)
169 */
170static inline void change_bit_cs(unsigned long nr, volatile unsigned long *ptr)
171{ 168{
172 unsigned long addr, mask; 169 unsigned long *addr = __bitops_word(nr, ptr);
170 unsigned long mask;
173 171
174 addr = (unsigned long) ptr;
175 /* calculate address for CS */
176 addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
177 /* make XOR mask */
178 mask = 1UL << (nr & (BITS_PER_LONG - 1)); 172 mask = 1UL << (nr & (BITS_PER_LONG - 1));
179 /* Do the atomic update. */
180 __BITOPS_LOOP(addr, mask, __BITOPS_XOR); 173 __BITOPS_LOOP(addr, mask, __BITOPS_XOR);
181} 174}
182 175
183/*
184 * SMP safe test_and_set_bit routine based on compare and swap (CS)
185 */
186static inline int 176static inline int
187test_and_set_bit_cs(unsigned long nr, volatile unsigned long *ptr) 177test_and_set_bit(unsigned long nr, volatile unsigned long *ptr)
188{ 178{
189 unsigned long addr, old, mask; 179 unsigned long *addr = __bitops_word(nr, ptr);
180 unsigned long old, mask;
190 181
191 addr = (unsigned long) ptr;
192 /* calculate address for CS */
193 addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
194 /* make OR/test mask */
195 mask = 1UL << (nr & (BITS_PER_LONG - 1)); 182 mask = 1UL << (nr & (BITS_PER_LONG - 1));
196 /* Do the atomic update. */
197 old = __BITOPS_LOOP(addr, mask, __BITOPS_OR); 183 old = __BITOPS_LOOP(addr, mask, __BITOPS_OR);
198 barrier(); 184 barrier();
199 return (old & mask) != 0; 185 return (old & mask) != 0;
200} 186}
201 187
202/*
203 * SMP safe test_and_clear_bit routine based on compare and swap (CS)
204 */
205static inline int 188static inline int
206test_and_clear_bit_cs(unsigned long nr, volatile unsigned long *ptr) 189test_and_clear_bit(unsigned long nr, volatile unsigned long *ptr)
207{ 190{
208 unsigned long addr, old, mask; 191 unsigned long *addr = __bitops_word(nr, ptr);
192 unsigned long old, mask;
209 193
210 addr = (unsigned long) ptr;
211 /* calculate address for CS */
212 addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
213 /* make AND/test mask */
214 mask = ~(1UL << (nr & (BITS_PER_LONG - 1))); 194 mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
215 /* Do the atomic update. */
216 old = __BITOPS_LOOP(addr, mask, __BITOPS_AND); 195 old = __BITOPS_LOOP(addr, mask, __BITOPS_AND);
217 barrier(); 196 barrier();
218 return (old & ~mask) != 0; 197 return (old & ~mask) != 0;
219} 198}
220 199
221/*
222 * SMP safe test_and_change_bit routine based on compare and swap (CS)
223 */
224static inline int 200static inline int
225test_and_change_bit_cs(unsigned long nr, volatile unsigned long *ptr) 201test_and_change_bit(unsigned long nr, volatile unsigned long *ptr)
226{ 202{
227 unsigned long addr, old, mask; 203 unsigned long *addr = __bitops_word(nr, ptr);
204 unsigned long old, mask;
228 205
229 addr = (unsigned long) ptr;
230 /* calculate address for CS */
231 addr += (nr ^ (nr & (BITS_PER_LONG - 1))) >> 3;
232 /* make XOR/test mask */
233 mask = 1UL << (nr & (BITS_PER_LONG - 1)); 206 mask = 1UL << (nr & (BITS_PER_LONG - 1));
234 /* Do the atomic update. */
235 old = __BITOPS_LOOP(addr, mask, __BITOPS_XOR); 207 old = __BITOPS_LOOP(addr, mask, __BITOPS_XOR);
236 barrier(); 208 barrier();
237 return (old & mask) != 0; 209 return (old & mask) != 0;
238} 210}
239#endif /* CONFIG_SMP */
240 211
241/*
242 * fast, non-SMP set_bit routine
243 */
244static inline void __set_bit(unsigned long nr, volatile unsigned long *ptr) 212static inline void __set_bit(unsigned long nr, volatile unsigned long *ptr)
245{ 213{
246 unsigned long addr; 214 unsigned char *addr = __bitops_byte(nr, ptr);
247
248 addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
249 asm volatile(
250 " oc %O0(1,%R0),%1"
251 : "+Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc");
252}
253
254static inline void
255__constant_set_bit(const unsigned long nr, volatile unsigned long *ptr)
256{
257 unsigned long addr;
258 215
259 addr = ((unsigned long) ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3); 216 *addr |= 1 << (nr & 7);
260 *(unsigned char *) addr |= 1 << (nr & 7);
261} 217}
262 218
263#define set_bit_simple(nr,addr) \
264(__builtin_constant_p((nr)) ? \
265 __constant_set_bit((nr),(addr)) : \
266 __set_bit((nr),(addr)) )
267
268/*
269 * fast, non-SMP clear_bit routine
270 */
271static inline void 219static inline void
272__clear_bit(unsigned long nr, volatile unsigned long *ptr) 220__clear_bit(unsigned long nr, volatile unsigned long *ptr)
273{ 221{
274 unsigned long addr; 222 unsigned char *addr = __bitops_byte(nr, ptr);
275 223
276 addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3); 224 *addr &= ~(1 << (nr & 7));
277 asm volatile(
278 " nc %O0(1,%R0),%1"
279 : "+Q" (*(char *) addr) : "Q" (_ni_bitmap[nr & 7]) : "cc");
280} 225}
281 226
282static inline void
283__constant_clear_bit(const unsigned long nr, volatile unsigned long *ptr)
284{
285 unsigned long addr;
286
287 addr = ((unsigned long) ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
288 *(unsigned char *) addr &= ~(1 << (nr & 7));
289}
290
291#define clear_bit_simple(nr,addr) \
292(__builtin_constant_p((nr)) ? \
293 __constant_clear_bit((nr),(addr)) : \
294 __clear_bit((nr),(addr)) )
295
296/*
297 * fast, non-SMP change_bit routine
298 */
299static inline void __change_bit(unsigned long nr, volatile unsigned long *ptr) 227static inline void __change_bit(unsigned long nr, volatile unsigned long *ptr)
300{ 228{
301 unsigned long addr; 229 unsigned char *addr = __bitops_byte(nr, ptr);
302
303 addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3);
304 asm volatile(
305 " xc %O0(1,%R0),%1"
306 : "+Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7]) : "cc");
307}
308
309static inline void
310__constant_change_bit(const unsigned long nr, volatile unsigned long *ptr)
311{
312 unsigned long addr;
313 230
314 addr = ((unsigned long) ptr) + ((nr ^ (BITS_PER_LONG - 8)) >> 3); 231 *addr ^= 1 << (nr & 7);
315 *(unsigned char *) addr ^= 1 << (nr & 7);
316} 232}
317 233
318#define change_bit_simple(nr,addr) \
319(__builtin_constant_p((nr)) ? \
320 __constant_change_bit((nr),(addr)) : \
321 __change_bit((nr),(addr)) )
322
323/*
324 * fast, non-SMP test_and_set_bit routine
325 */
326static inline int 234static inline int
327test_and_set_bit_simple(unsigned long nr, volatile unsigned long *ptr) 235__test_and_set_bit(unsigned long nr, volatile unsigned long *ptr)
328{ 236{
329 unsigned long addr; 237 unsigned char *addr = __bitops_byte(nr, ptr);
330 unsigned char ch; 238 unsigned char ch;
331 239
332 addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3); 240 ch = *addr;
333 ch = *(unsigned char *) addr; 241 *addr |= 1 << (nr & 7);
334 asm volatile(
335 " oc %O0(1,%R0),%1"
336 : "+Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7])
337 : "cc", "memory");
338 return (ch >> (nr & 7)) & 1; 242 return (ch >> (nr & 7)) & 1;
339} 243}
340#define __test_and_set_bit(X,Y) test_and_set_bit_simple(X,Y)
341 244
342/*
343 * fast, non-SMP test_and_clear_bit routine
344 */
345static inline int 245static inline int
346test_and_clear_bit_simple(unsigned long nr, volatile unsigned long *ptr) 246__test_and_clear_bit(unsigned long nr, volatile unsigned long *ptr)
347{ 247{
348 unsigned long addr; 248 unsigned char *addr = __bitops_byte(nr, ptr);
349 unsigned char ch; 249 unsigned char ch;
350 250
351 addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3); 251 ch = *addr;
352 ch = *(unsigned char *) addr; 252 *addr &= ~(1 << (nr & 7));
353 asm volatile(
354 " nc %O0(1,%R0),%1"
355 : "+Q" (*(char *) addr) : "Q" (_ni_bitmap[nr & 7])
356 : "cc", "memory");
357 return (ch >> (nr & 7)) & 1; 253 return (ch >> (nr & 7)) & 1;
358} 254}
359#define __test_and_clear_bit(X,Y) test_and_clear_bit_simple(X,Y)
360 255
361/*
362 * fast, non-SMP test_and_change_bit routine
363 */
364static inline int 256static inline int
365test_and_change_bit_simple(unsigned long nr, volatile unsigned long *ptr) 257__test_and_change_bit(unsigned long nr, volatile unsigned long *ptr)
366{ 258{
367 unsigned long addr; 259 unsigned char *addr = __bitops_byte(nr, ptr);
368 unsigned char ch; 260 unsigned char ch;
369 261
370 addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3); 262 ch = *addr;
371 ch = *(unsigned char *) addr; 263 *addr ^= 1 << (nr & 7);
372 asm volatile(
373 " xc %O0(1,%R0),%1"
374 : "+Q" (*(char *) addr) : "Q" (_oi_bitmap[nr & 7])
375 : "cc", "memory");
376 return (ch >> (nr & 7)) & 1; 264 return (ch >> (nr & 7)) & 1;
377} 265}
378#define __test_and_change_bit(X,Y) test_and_change_bit_simple(X,Y)
379
380#ifdef CONFIG_SMP
381#define set_bit set_bit_cs
382#define clear_bit clear_bit_cs
383#define change_bit change_bit_cs
384#define test_and_set_bit test_and_set_bit_cs
385#define test_and_clear_bit test_and_clear_bit_cs
386#define test_and_change_bit test_and_change_bit_cs
387#else
388#define set_bit set_bit_simple
389#define clear_bit clear_bit_simple
390#define change_bit change_bit_simple
391#define test_and_set_bit test_and_set_bit_simple
392#define test_and_clear_bit test_and_clear_bit_simple
393#define test_and_change_bit test_and_change_bit_simple
394#endif
395
396 266
397/* 267static inline int test_bit(unsigned long nr, const volatile unsigned long *ptr)
398 * This routine doesn't need to be atomic.
399 */
400
401static inline int __test_bit(unsigned long nr, const volatile unsigned long *ptr)
402{ 268{
403 unsigned long addr; 269 const volatile unsigned char *addr;
404 unsigned char ch;
405 270
406 addr = (unsigned long) ptr + ((nr ^ (BITS_PER_LONG - 8)) >> 3); 271 addr = ((const volatile unsigned char *)ptr);
407 ch = *(volatile unsigned char *) addr; 272 addr += (nr ^ (BITS_PER_LONG - 8)) >> 3;
408 return (ch >> (nr & 7)) & 1; 273 return (*addr >> (nr & 7)) & 1;
409}
410
411static inline int
412__constant_test_bit(unsigned long nr, const volatile unsigned long *addr) {
413 return (((volatile char *) addr)
414 [(nr^(BITS_PER_LONG-8))>>3] & (1<<(nr&7))) != 0;
415} 274}
416 275
417#define test_bit(nr,addr) \
418(__builtin_constant_p((nr)) ? \
419 __constant_test_bit((nr),(addr)) : \
420 __test_bit((nr),(addr)) )
421
422/* 276/*
423 * Optimized find bit helper functions. 277 * Optimized find bit helper functions.
424 */ 278 */