xref: /linux/arch/s390/include/asm/entry-percpu.h (revision bb29b957eaaa15be33243550d9ee576c2d601669)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef ARCH_S390_ENTRY_PERCPU_H
3 #define ARCH_S390_ENTRY_PERCPU_H
4 
5 #include <linux/bitfield.h>
6 #include <linux/percpu.h>
7 #include <asm/lowcore.h>
8 #include <asm/ptrace.h>
9 
10 static __always_inline void percpu_entry(struct pt_regs *regs)
11 {
12 	struct lowcore *lc = get_lowcore();
13 
14 	regs->cpu = lc->cpu_nr;
15 	regs->percpu_register = lc->percpu_register;
16 	lc->percpu_register = 0;
17 }
18 
19 static __always_inline void percpu_exit(struct pt_regs *regs)
20 {
21 	unsigned char regval, regpcp, regoff, regptr;
22 	struct lowcore *lc = get_lowcore();
23 
24 	if (!regs->percpu_register)
25 		return;
26 	regval = regs->percpu_register;
27 	lc->percpu_register = regval;
28 	/* Migrated to a different CPU? */
29 	if (regs->cpu == lc->cpu_nr)
30 		return;
31 	regpcp = FIELD_GET(PCPU_REG_PCP, regval);
32 	regoff = FIELD_GET(PCPU_REG_OFF, regval);
33 	regptr = regoff + 1;
34 	/*
35 	 * Update register 'regoff' with the current CPU's percpu offset,
36 	 * and recalculate and update current CPU's percpu variable address
37 	 * contained in register 'regptr'.
38 	 */
39 	regs->gprs[regoff] = lc->percpu_offset;
40 	regs->gprs[regptr] = regs->gprs[regpcp] + regs->gprs[regoff];
41 }
42 
43 #endif
44