projects/linux·blob master · refs

490 lines · 17.8 KiB

1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef __ARCH_S390_PERCPU__
3#define __ARCH_S390_PERCPU__
4
5#include <linux/preempt.h>
6#include <asm/cmpxchg.h>
7#include <asm/march.h>
8#include <asm/asm.h>
9
10/*
11 * s390 uses its own implementation for per cpu data, the offset of
12 * the cpu local data area is cached in the cpu's lowcore memory.
13 */
14#define __my_cpu_offset get_lowcore()->percpu_offset
15
16#define arch_raw_cpu_ptr(_ptr) \
17({ \
18 unsigned long tcp_ptr__; \
19 \
20 tcp_ptr__ = (__force unsigned long)(_ptr); \
21 asm_inline volatile( \
22 ALTERNATIVE("ag %[__ptr__],%[offzero](%%r0)\n", \
23 "ag %[__ptr__],%[offalt](%%r0)\n", \
24 ALT_FEATURE(MFEATURE_LOWCORE)) \
25 : [__ptr__] "+d" (tcp_ptr__) \
26 : [offzero] "i" (LC_PERCPU_OFFSET), \
27 [offalt] "i" (LC_PERCPU_OFFSET + LOWCORE_ALT_ADDRESS), \
28 "m" (((struct lowcore *)0)->percpu_offset) \
29 : "cc"); \
30 (TYPEOF_UNQUAL(*(_ptr)) __force __kernel *)tcp_ptr__; \
31})
32
33/*
34 * We use a compare-and-swap loop since that uses less cpu cycles than
35 * disabling and enabling interrupts like the generic variant would do.
36 */
37#define arch_this_cpu_to_op_simple(pcp, val, op) \
38({ \
39 typedef typeof(pcp) pcp_op_T__; \
40 pcp_op_T__ old__, new__, prev__; \
41 pcp_op_T__ *ptr__; \
42 preempt_disable_notrace(); \
43 ptr__ = raw_cpu_ptr(&(pcp)); \
44 prev__ = READ_ONCE(*ptr__); \
45 do { \
46 old__ = prev__; \
47 new__ = old__ op (val); \
48 prev__ = cmpxchg(ptr__, old__, new__); \
49 } while (prev__ != old__); \
50 preempt_enable_notrace(); \
51 new__; \
52})
53
54#define this_cpu_add_1(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
55#define this_cpu_add_2(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
56#define this_cpu_add_return_1(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
57#define this_cpu_add_return_2(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
58#define this_cpu_and_1(pcp, val) arch_this_cpu_to_op_simple(pcp, val, &)
59#define this_cpu_and_2(pcp, val) arch_this_cpu_to_op_simple(pcp, val, &)
60#define this_cpu_or_1(pcp, val) arch_this_cpu_to_op_simple(pcp, val, |)
61#define this_cpu_or_2(pcp, val) arch_this_cpu_to_op_simple(pcp, val, |)
62
63/*
64 * Macros to be used for percpu code section based on atomic instructions.
65 *
66 * Avoid the need to use preempt_disable() / preempt_enable() pairs and the
67 * conditional preempt_schedule_notrace() function calls which come with
68 * this. The idea is that this_cpu operations based on atomic instructions are
69 * guarded with mviy instructions:
70 *
71 * - The first mviy instruction writes the register number of the percpu address
72 * variable and the even register number of a register pair (which encodes two
73 * registers: the even register for the percpu offset and the odd register for
74 * the percpu pointer) to lowcore. This also indicates that a percpu code
75 * section is executed.
76 *
77 * - The mviy instruction is followed by the lg instruction which loads the
78 * percpu offset into the even register of the pair and the la instruction
79 * which adds the percpu offset and the percpu address into the odd register
80 * of the pair (the percpu pointer register).
81 *
82 * - Afterwards the atomic percpu operation follows.
83 *
84 * - Then a second mviy instruction writes a zero to lowcore, which indicates
85 * the end of the percpu code section.
86 *
87 * - In case of an interrupt/exception/nmi the encoded register numbers which
88 * were written to lowcore are copied to the exception frame (pt_regs), and a
89 * zero is written to lowcore.
90 *
91 * - On return to the previous context it is checked if a percpu code section
92 * was executed (saved register value not zero), and if the process was
93 * migrated to a different cpu. The content of the percpu offset register
94 * (even register of the pair) is reloaded with the current cpu's percpu
95 * offset and the percpu pointer register (odd register of the pair) is
96 * recalculated so it points to the percpu variable of the new cpu.
97 *
98 * Inline assemblies making use of this typically have a code sequence like:
99 *
100 * __PCPU_BEGIN(...) <- start of percpu code section
101 * atomic_op <- atomic op
102 * __PCPU_END(...) <- end of percpu code section
103 */
104
105#define LC_ALT_ADDR __stringify(LOWCORE_ALT_ADDRESS)
106
107#define DEFINE_GR_NUM \
108 ".macro _GR_NUM opd, gr\n" \
109 ".set \\opd,255\n" \
110 ".irp rs,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15\n" \
111 " .ifc \\gr,%%r\\rs\n" \
112 " \\opd = \\rs\n" \
113 " .endif\n" \
114 ".endr\n" \
115 ".if \\opd == 255\n" \
116 " .error \"Illegal register number\"\n" \
117 ".endif\n" \
118 ".endm\n"
119
120#define UNDEF_GR_NUM \
121 ".purgem _GR_NUM\n"
122
123#define PCPU_REG_PCP_SHIFT 0
124#define PCPU_REG_PCP GENMASK(3, 0)
125#define PCPU_REG_OFF_SHIFT 4
126#define PCPU_REG_OFF GENMASK(7, 4)
127
128#define __PCPU_MVIY(lcreg, imm) \
129 ALTERNATIVE(" mviy " lcreg "(%%r0)," imm "\n", \
130 " mviy " lcreg "+" LC_ALT_ADDR "(%%r0)," imm "\n", \
131 ALT_FEATURE(MFEATURE_LOWCORE))
132
133#define __PCPU_LG(regoff, lcoff) \
134 ALTERNATIVE(" lg " regoff ", " lcoff "(%%r0)\n", \
135 " lg " regoff ", " lcoff "+" LC_ALT_ADDR "(%%r0)\n", \
136 ALT_FEATURE(MFEATURE_LOWCORE))
137
138#define __PCPU_LA(regptr, regoff, regpcp) \
139 " la " regptr ",0(" regoff "," regpcp ")\n"
140
141#define __PCPU_CALC_REGVAL(regpcp, regoff) \
142 "(" regpcp " << " __stringify(PCPU_REG_PCP_SHIFT) ") |" \
143 "(" regoff " << " __stringify(PCPU_REG_OFF_SHIFT) ")"
144
145#define __PCPU_CHECK_REGS(regpcp, regoff, regptr) \
146 ".if " regoff " & 1\n" \
147 " .error \"Percpu offset register must be even\"\n" \
148 ".endif\n" \
149 ".if (" regpcp " == 0) || (" regoff " == 0)\n" \
150 " .error \"Percpu address and offset register must be non-zero\"\n"\
151 ".endif\n" \
152 ".if " regptr " != " regoff " + 1\n" \
153 " .error \"Percpu pointer and offset register must be a pair\"\n" \
154 ".endif\n" \
155 ".if (" regpcp " == " regoff ") || (" regpcp " == " regptr ")\n" \
156 " .error \"Percpu registers must be distinct\"\n" \
157 ".endif\n"
158
159#define __PCPU_BEGIN(lcreg, lcoff, regpcp, regoff, regptr) \
160 DEFINE_GR_NUM \
161 "_GR_NUM .Lregpcp, " regpcp "\n" \
162 "_GR_NUM .Lregoff, " regoff "\n" \
163 "_GR_NUM .Lregptr, " regptr "\n" \
164 UNDEF_GR_NUM \
165 __PCPU_CHECK_REGS(".Lregpcp", ".Lregoff", ".Lregptr") \
166 ".set .Lregval, " __PCPU_CALC_REGVAL(".Lregpcp", ".Lregoff") "\n" \
167 __PCPU_MVIY(lcreg, ".Lregval") \
168 __PCPU_LG(regoff, lcoff) \
169 __PCPU_LA(regptr, regoff, regpcp)
170
171#define __PCPU_END(lcreg) \
172 __PCPU_MVIY(lcreg, "0")
173
174#ifndef MARCH_HAS_Z196_FEATURES
175
176#define this_cpu_add_4(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
177#define this_cpu_add_8(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
178#define this_cpu_add_return_4(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
179#define this_cpu_add_return_8(pcp, val) arch_this_cpu_to_op_simple(pcp, val, +)
180#define this_cpu_and_4(pcp, val) arch_this_cpu_to_op_simple(pcp, val, &)
181#define this_cpu_and_8(pcp, val) arch_this_cpu_to_op_simple(pcp, val, &)
182#define this_cpu_or_4(pcp, val) arch_this_cpu_to_op_simple(pcp, val, |)
183#define this_cpu_or_8(pcp, val) arch_this_cpu_to_op_simple(pcp, val, |)
184
185#else /* MARCH_HAS_Z196_FEATURES */
186
187#define arch_this_cpu_add(pcp, val, op1, op2, szcast) \
188do { \
189 typedef typeof(pcp) pcp_op_T__; \
190 union register_pair rp__; \
191 pcp_op_T__ val__ = (val); \
192 pcp_op_T__ *ptr__; \
193 \
194 ptr__ = PERCPU_PTR(&(pcp)); \
195 if (__builtin_constant_p(val__) && \
196 ((szcast)val__ > -129) && ((szcast)val__ < 128)) { \
197 asm_inline volatile( \
198 __PCPU_BEGIN("%[lcreg]","%[lcoff]","%[ptr__]", \
199 "%[pair__]","%N[pair__]") \
200 op2 " 0(%N[pair__]),%[val__]\n" \
201 __PCPU_END("%[lcreg]") \
202 : [pair__] "=&a" (rp__.pair), "+m" (*ptr__), \
203 "=m" (((struct lowcore *)0)->percpu_register) \
204 : [val__] "i" ((szcast)val__), [ptr__] "a" (ptr__), \
205 [lcreg] "i" (LC_PERCPU_REGISTER), \
206 [lcoff] "i" (LC_PERCPU_OFFSET), \
207 "m" (((struct lowcore *)0)->percpu_offset) \
208 : "cc"); \
209 } else { \
210 asm_inline volatile( \
211 __PCPU_BEGIN("%[lcreg]","%[lcoff]","%[ptr__]", \
212 "%[pair__]","%N[pair__]") \
213 op1 " %[val__],%[val__],0(%N[pair__])\n" \
214 __PCPU_END("%[lcreg]") \
215 : [val__] "+&d" (val__), [pair__] "=&a" (rp__.pair), \
216 "+m" (*ptr__), \
217 "=m" (((struct lowcore *)0)->percpu_register) \
218 : [ptr__] "a" (ptr__), \
219 [lcreg] "i" (LC_PERCPU_REGISTER), \
220 [lcoff] "i" (LC_PERCPU_OFFSET), \
221 "m" (((struct lowcore *)0)->percpu_offset) \
222 : "cc"); \
223 } \
224} while (0)
225
226#define this_cpu_add_4(pcp, val) arch_this_cpu_add(pcp, val, "laa", "asi", int)
227#define this_cpu_add_8(pcp, val) arch_this_cpu_add(pcp, val, "laag", "agsi", long)
228
229#define arch_this_cpu_add_return(pcp, val, op) \
230({ \
231 typedef typeof(pcp) pcp_op_T__; \
232 union register_pair rp__; \
233 pcp_op_T__ val__ = (val); \
234 pcp_op_T__ old__, *ptr__; \
235 \
236 ptr__ = PERCPU_PTR(&(pcp)); \
237 asm_inline volatile( \
238 __PCPU_BEGIN("%[lcreg]","%[lcoff]","%[ptr__]", \
239 "%[pair__]","%N[pair__]") \
240 op " %[old__],%[val__],0(%N[pair__])\n" \
241 __PCPU_END("%[lcreg]") \
242 : [old__] "=&d" (old__), [pair__] "=&a" (rp__.pair), \
243 "+m" (*ptr__), \
244 "=m" (((struct lowcore *)0)->percpu_register) \
245 : [val__] "d" (val__), [ptr__] "a" (ptr__), \
246 [lcreg] "i" (LC_PERCPU_REGISTER), \
247 [lcoff] "i" (LC_PERCPU_OFFSET), \
248 "m" (((struct lowcore *)0)->percpu_offset) \
249 : "cc"); \
250 old__ + val__; \
251})
252
253#define this_cpu_add_return_4(pcp, val) arch_this_cpu_add_return(pcp, val, "laa")
254#define this_cpu_add_return_8(pcp, val) arch_this_cpu_add_return(pcp, val, "laag")
255
256#define arch_this_cpu_to_op(pcp, val, op) \
257do { \
258 typedef typeof(pcp) pcp_op_T__; \
259 union register_pair rp__; \
260 pcp_op_T__ val__ = (val); \
261 pcp_op_T__ *ptr__; \
262 \
263 ptr__ = PERCPU_PTR(&(pcp)); \
264 asm_inline volatile( \
265 __PCPU_BEGIN("%[lcreg]","%[lcoff]","%[ptr__]", \
266 "%[pair__]","%N[pair__]") \
267 op " %[val__],%[val__],0(%N[pair__])\n" \
268 __PCPU_END("%[lcreg]") \
269 : [val__] "+&d" (val__), [pair__] "=&a" (rp__.pair), \
270 "+m" (*ptr__), \
271 "=m" (((struct lowcore *)0)->percpu_register) \
272 : [ptr__] "a" (ptr__), \
273 [lcreg] "i" (LC_PERCPU_REGISTER), \
274 [lcoff] "i" (LC_PERCPU_OFFSET), \
275 "m" (((struct lowcore *)0)->percpu_offset) \
276 : "cc"); \
277} while (0)
278
279#define this_cpu_and_4(pcp, val) arch_this_cpu_to_op(pcp, val, "lan")
280#define this_cpu_and_8(pcp, val) arch_this_cpu_to_op(pcp, val, "lang")
281#define this_cpu_or_4(pcp, val) arch_this_cpu_to_op(pcp, val, "lao")
282#define this_cpu_or_8(pcp, val) arch_this_cpu_to_op(pcp, val, "laog")
283
284#endif /* MARCH_HAS_Z196_FEATURES */
285
286#define arch_this_cpu_read(pcp, op) \
287({ \
288 typedef typeof(pcp) pcp_op_T__; \
289 union register_pair rp__; \
290 unsigned long res__; \
291 pcp_op_T__ *ptr__; \
292 \
293 ptr__ = PERCPU_PTR(&(pcp)); \
294 asm_inline volatile( \
295 __PCPU_BEGIN("%[lcreg]","%[lcoff]","%[ptr__]", \
296 "%[pair__]","%N[pair__]") \
297 op " %[res__],0(%N[pair__])\n" \
298 __PCPU_END("%[lcreg]") \
299 : [res__] "=&d" (res__), [pair__] "=&a" (rp__.pair), \
300 "=m" (((struct lowcore *)0)->percpu_register) \
301 : [ptr__] "a" (ptr__), \
302 [lcreg] "i" (LC_PERCPU_REGISTER), \
303 [lcoff] "i" (LC_PERCPU_OFFSET), \
304 "m" (*ptr__), \
305 "m" (((struct lowcore *)0)->percpu_offset) \
306 : "cc"); \
307 (pcp_op_T__)res__; \
308})
309
310#define this_cpu_read_1(pcp) arch_this_cpu_read(pcp, "llgc")
311#define this_cpu_read_2(pcp) arch_this_cpu_read(pcp, "llgh")
312#define this_cpu_read_4(pcp) arch_this_cpu_read(pcp, "llgf")
313#define this_cpu_read_8(pcp) arch_this_cpu_read(pcp, "lg")
314
315#define arch_this_cpu_write(pcp, val, op) \
316do { \
317 typedef typeof(pcp) pcp_op_T__; \
318 union register_pair rp__; \
319 pcp_op_T__ *ptr__, val__ = (val); \
320 \
321 ptr__ = PERCPU_PTR(&(pcp)); \
322 asm_inline volatile( \
323 __PCPU_BEGIN("%[lcreg]","%[lcoff]","%[ptr__]", \
324 "%[pair__]","%N[pair__]") \
325 op " %[val__],0(%N[pair__])\n" \
326 __PCPU_END("%[lcreg]") \
327 : [pair__] "=&a" (rp__.pair), "=m" (*ptr__), \
328 "=m" (((struct lowcore *)0)->percpu_register) \
329 : [val__] "d" (val__), [ptr__] "a" (ptr__), \
330 [lcreg] "i" (LC_PERCPU_REGISTER), \
331 [lcoff] "i" (LC_PERCPU_OFFSET), \
332 "m" (((struct lowcore *)0)->percpu_offset) \
333 : "cc"); \
334} while (0)
335
336#define this_cpu_write_1(pcp, val) arch_this_cpu_write(pcp, val, "stc")
337#define this_cpu_write_2(pcp, val) arch_this_cpu_write(pcp, val, "sth")
338#define this_cpu_write_4(pcp, val) arch_this_cpu_write(pcp, val, "st")
339#define this_cpu_write_8(pcp, val) arch_this_cpu_write(pcp, val, "stg")
340
341#define arch_this_cpu_cmpxchg_simple(pcp, oval, nval) \
342({ \
343 typedef typeof(pcp) pcp_op_T__; \
344 pcp_op_T__ ret__; \
345 pcp_op_T__ *ptr__; \
346 preempt_disable_notrace(); \
347 ptr__ = raw_cpu_ptr(&(pcp)); \
348 ret__ = cmpxchg(ptr__, oval, nval); \
349 preempt_enable_notrace(); \
350 ret__; \
351})
352
353#define arch_this_cpu_cmpxchg(pcp, oval, nval, op) \
354({ \
355 typedef typeof(pcp) pcp_op_T__; \
356 pcp_op_T__ old__ = (oval), new__ = (nval); \
357 union register_pair rp__; \
358 pcp_op_T__ *ptr__; \
359 \
360 ptr__ = PERCPU_PTR(&(pcp)); \
361 asm_inline volatile( \
362 __PCPU_BEGIN("%[lcreg]","%[lcoff]","%[ptr__]", \
363 "%[pair__]","%N[pair__]") \
364 op " %[old__],%[new__],0(%N[pair__])\n" \
365 __PCPU_END("%[lcreg]") \
366 : [old__] "+&d" (old__), [pair__] "=&a" (rp__.pair), \
367 "+m" (*ptr__), \
368 "=m" (((struct lowcore *)0)->percpu_register) \
369 : [new__] "d" (new__), [ptr__] "a" (ptr__), \
370 [lcreg] "i" (LC_PERCPU_REGISTER), \
371 [lcoff] "i" (LC_PERCPU_OFFSET), \
372 "m" (((struct lowcore *)0)->percpu_offset) \
373 : "memory", "cc"); \
374 old__; \
375})
376
377#define this_cpu_cmpxchg_1(pcp, oval, nval) arch_this_cpu_cmpxchg_simple(pcp, oval, nval)
378#define this_cpu_cmpxchg_2(pcp, oval, nval) arch_this_cpu_cmpxchg_simple(pcp, oval, nval)
379#define this_cpu_cmpxchg_4(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval, "cs")
380#define this_cpu_cmpxchg_8(pcp, oval, nval) arch_this_cpu_cmpxchg(pcp, oval, nval, "csg")
381
382#define this_cpu_cmpxchg64(pcp, o, n) this_cpu_cmpxchg_8(pcp, o, n)
383
384#define this_cpu_cmpxchg128(pcp, oval, nval) \
385({ \
386 typedef typeof(pcp) pcp_op_T__; \
387 u128 old__ = (oval), new__ = (nval); \
388 union register_pair rp__; \
389 pcp_op_T__ *ptr__; \
390 \
391 ptr__ = PERCPU_PTR(&(pcp)); \
392 asm_inline volatile( \
393 __PCPU_BEGIN("%[lcreg]","%[lcoff]","%[ptr__]", \
394 "%[pair__]","%N[pair__]") \
395 " cdsg %[old__],%[new__],0(%N[pair__])\n" \
396 __PCPU_END("%[lcreg]") \
397 : [old__] "+&d" (old__), [pair__] "=&a" (rp__.pair), \
398 "+m" (*ptr__), \
399 "=m" (((struct lowcore *)0)->percpu_register) \
400 : [new__] "d" (new__), [ptr__] "a" (ptr__), \
401 [lcreg] "i" (LC_PERCPU_REGISTER), \
402 [lcoff] "i" (LC_PERCPU_OFFSET), \
403 "m" (((struct lowcore *)0)->percpu_offset) \
404 : "memory", "cc"); \
405 old__; \
406})
407
408#ifdef __HAVE_ASM_FLAG_OUTPUTS__
409
410#define arch_this_cpu_try_cmpxchg(pcp, ovalp, nval, op) \
411({ \
412 typedef typeof(pcp) pcp_op_T__; \
413 typeof(ovalp) ovalp__ = (ovalp); \
414 pcp_op_T__ old__ = *ovalp__; \
415 pcp_op_T__ new__ = (nval); \
416 union register_pair rp__; \
417 pcp_op_T__ *ptr__; \
418 int cc__; \
419 \
420 ptr__ = PERCPU_PTR(&(pcp)); \
421 asm_inline volatile( \
422 __PCPU_BEGIN("%[lcreg]","%[lcoff]","%[ptr__]", \
423 "%[pair__]","%N[pair__]") \
424 op " %[old__],%[new__],0(%N[pair__])\n" \
425 __PCPU_END("%[lcreg]") \
426 : [old__] "+&d" (old__), [pair__] "=&a" (rp__.pair), \
427 "+m" (*ptr__), "=@cc" (cc__), \
428 "=m" (((struct lowcore *)0)->percpu_register) \
429 : [new__] "d" (new__), [ptr__] "a" (ptr__), \
430 [lcreg] "i" (LC_PERCPU_REGISTER), \
431 [lcoff] "i" (LC_PERCPU_OFFSET), \
432 "m" (((struct lowcore *)0)->percpu_offset) \
433 : "memory"); \
434 if (unlikely(cc__)) \
435 *ovalp__ = old__; \
436 likely(cc__ == 0); \
437})
438
439#define this_cpu_try_cmpxchg_4(pcp, ovalp, nval) arch_this_cpu_try_cmpxchg(pcp, ovalp, nval, "cs")
440#define this_cpu_try_cmpxchg_8(pcp, ovalp, nval) arch_this_cpu_try_cmpxchg(pcp, ovalp, nval, "csg")
441
442#define this_cpu_try_cmpxchg64(pcp, ovalp, nval) this_cpu_try_cmpxchg_8(pcp, ovalp, nval)
443
444#endif /* __HAVE_ASM_FLAG_OUTPUTS__ */
445
446#define arch_this_cpu_xchg_simple(pcp, nval) \
447({ \
448 typeof(pcp) *ptr__; \
449 typeof(pcp) ret__; \
450 preempt_disable_notrace(); \
451 ptr__ = raw_cpu_ptr(&(pcp)); \
452 ret__ = xchg(ptr__, nval); \
453 preempt_enable_notrace(); \
454 ret__; \
455})
456
457#define arch_this_cpu_xchg(pcp, nval, ldop, csop) \
458({ \
459 typedef typeof(pcp) pcp_op_T__; \
460 pcp_op_T__ old__, new__ = (nval); \
461 union register_pair rp__; \
462 pcp_op_T__ *ptr__; \
463 \
464 ptr__ = PERCPU_PTR(&(pcp)); \
465 asm_inline volatile( \
466 __PCPU_BEGIN("%[lcreg]","%[lcoff]","%[ptr__]", \
467 "%[pair__]","%N[pair__]") \
468 " " ldop " %[old__],0(%N[pair__])\n" \
469 "0: " csop " %[old__],%[new__],0(%N[pair__])\n"\
470 " jnz 0b\n" \
471 __PCPU_END("%[lcreg]") \
472 : [old__] "=&d" (old__), [pair__] "=&a" (rp__.pair), \
473 "+m" (*ptr__), \
474 "=m" (((struct lowcore *)0)->percpu_register) \
475 : [new__] "d" (new__), [ptr__] "a" (ptr__), \
476 [lcreg] "i" (LC_PERCPU_REGISTER), \
477 [lcoff] "i" (LC_PERCPU_OFFSET), \
478 "m" (((struct lowcore *)0)->percpu_offset) \
479 : "memory", "cc"); \
480 old__; \
481})
482
483#define this_cpu_xchg_1(pcp, nval) arch_this_cpu_xchg_simple(pcp, nval)
484#define this_cpu_xchg_2(pcp, nval) arch_this_cpu_xchg_simple(pcp, nval)
485#define this_cpu_xchg_4(pcp, nval) arch_this_cpu_xchg(pcp, nval, "l", "cs")
486#define this_cpu_xchg_8(pcp, nval) arch_this_cpu_xchg(pcp, nval, "lg", "csg")
487
488#include <asm-generic/percpu.h>
489
490#endif /* __ARCH_S390_PERCPU__ */