xref: /openbmc/linux/arch/s390/include/asm/switch_to.h (revision 5104d265)
1 /*
2  * Copyright IBM Corp. 1999, 2009
3  *
4  * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
5  */
6 
7 #ifndef __ASM_SWITCH_TO_H
8 #define __ASM_SWITCH_TO_H
9 
10 #include <linux/thread_info.h>
11 
12 extern struct task_struct *__switch_to(void *, void *);
13 extern void update_cr_regs(struct task_struct *task);
14 
15 static inline void save_fp_regs(s390_fp_regs *fpregs)
16 {
17 	asm volatile(
18 		"	std	0,%O0+8(%R0)\n"
19 		"	std	2,%O0+24(%R0)\n"
20 		"	std	4,%O0+40(%R0)\n"
21 		"	std	6,%O0+56(%R0)"
22 		: "=Q" (*fpregs) : "Q" (*fpregs));
23 	if (!MACHINE_HAS_IEEE)
24 		return;
25 	asm volatile(
26 		"	stfpc	%0\n"
27 		"	std	1,%O0+16(%R0)\n"
28 		"	std	3,%O0+32(%R0)\n"
29 		"	std	5,%O0+48(%R0)\n"
30 		"	std	7,%O0+64(%R0)\n"
31 		"	std	8,%O0+72(%R0)\n"
32 		"	std	9,%O0+80(%R0)\n"
33 		"	std	10,%O0+88(%R0)\n"
34 		"	std	11,%O0+96(%R0)\n"
35 		"	std	12,%O0+104(%R0)\n"
36 		"	std	13,%O0+112(%R0)\n"
37 		"	std	14,%O0+120(%R0)\n"
38 		"	std	15,%O0+128(%R0)\n"
39 		: "=Q" (*fpregs) : "Q" (*fpregs));
40 }
41 
42 static inline void restore_fp_regs(s390_fp_regs *fpregs)
43 {
44 	asm volatile(
45 		"	ld	0,%O0+8(%R0)\n"
46 		"	ld	2,%O0+24(%R0)\n"
47 		"	ld	4,%O0+40(%R0)\n"
48 		"	ld	6,%O0+56(%R0)"
49 		: : "Q" (*fpregs));
50 	if (!MACHINE_HAS_IEEE)
51 		return;
52 	asm volatile(
53 		"	lfpc	%0\n"
54 		"	ld	1,%O0+16(%R0)\n"
55 		"	ld	3,%O0+32(%R0)\n"
56 		"	ld	5,%O0+48(%R0)\n"
57 		"	ld	7,%O0+64(%R0)\n"
58 		"	ld	8,%O0+72(%R0)\n"
59 		"	ld	9,%O0+80(%R0)\n"
60 		"	ld	10,%O0+88(%R0)\n"
61 		"	ld	11,%O0+96(%R0)\n"
62 		"	ld	12,%O0+104(%R0)\n"
63 		"	ld	13,%O0+112(%R0)\n"
64 		"	ld	14,%O0+120(%R0)\n"
65 		"	ld	15,%O0+128(%R0)\n"
66 		: : "Q" (*fpregs));
67 }
68 
69 static inline void save_access_regs(unsigned int *acrs)
70 {
71 	asm volatile("stam 0,15,%0" : "=Q" (*acrs));
72 }
73 
74 static inline void restore_access_regs(unsigned int *acrs)
75 {
76 	asm volatile("lam 0,15,%0" : : "Q" (*acrs));
77 }
78 
79 #define switch_to(prev,next,last) do {					\
80 	if (prev->mm) {							\
81 		save_fp_regs(&prev->thread.fp_regs);			\
82 		save_access_regs(&prev->thread.acrs[0]);		\
83 		save_ri_cb(prev->thread.ri_cb);				\
84 	}								\
85 	if (next->mm) {							\
86 		restore_fp_regs(&next->thread.fp_regs);			\
87 		restore_access_regs(&next->thread.acrs[0]);		\
88 		restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);	\
89 		update_cr_regs(next);					\
90 	}								\
91 	prev = __switch_to(prev,next);					\
92 } while (0)
93 
94 #define finish_arch_switch(prev) do {					     \
95 	set_fs(current->thread.mm_segment);				     \
96 } while (0)
97 
98 #endif /* __ASM_SWITCH_TO_H */
99