switch_to.h 4.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
/*
 * Copyright IBM Corp. 1999, 2009
 *
 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
 */

#ifndef __ASM_SWITCH_TO_H
#define __ASM_SWITCH_TO_H

#include <linux/thread_info.h>
11
#include <asm/ptrace.h>
12 13

extern struct task_struct *__switch_to(void *, void *);
14
extern void update_cr_regs(struct task_struct *task);
15

16
static inline int test_fp_ctl(u32 fpc)
17
{
18 19 20 21 22 23
	u32 orig_fpc;
	int rc;

	if (!MACHINE_HAS_IEEE)
		return 0;

24
	asm volatile(
25 26 27 28 29 30 31 32 33 34 35 36 37
		"	efpc    %1\n"
		"	sfpc	%2\n"
		"0:	sfpc	%1\n"
		"	la	%0,0\n"
		"1:\n"
		EX_TABLE(0b,1b)
		: "=d" (rc), "=d" (orig_fpc)
		: "d" (fpc), "0" (-EINVAL));
	return rc;
}

static inline void save_fp_ctl(u32 *fpc)
{
38 39
	if (!MACHINE_HAS_IEEE)
		return;
40

41
	asm volatile(
42 43
		"       stfpc   %0\n"
		: "+Q" (*fpc));
44 45
}

46
static inline int restore_fp_ctl(u32 *fpc)
47
{
48 49 50 51 52
	int rc;

	if (!MACHINE_HAS_IEEE)
		return 0;

53
	asm volatile(
54 55
		"	lfpc    %1\n"
		"0:	la	%0,0\n"
56 57 58 59 60 61 62 63 64 65 66 67
		"1:\n"
		EX_TABLE(0b,1b)
		: "=d" (rc) : "Q" (*fpc), "0" (-EINVAL));
	return rc;
}

static inline void save_fp_regs(freg_t *fprs)
{
	asm volatile("std 0,%0" : "=Q" (fprs[0]));
	asm volatile("std 2,%0" : "=Q" (fprs[2]));
	asm volatile("std 4,%0" : "=Q" (fprs[4]));
	asm volatile("std 6,%0" : "=Q" (fprs[6]));
68 69
	if (!MACHINE_HAS_IEEE)
		return;
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
	asm volatile("std 1,%0" : "=Q" (fprs[1]));
	asm volatile("std 3,%0" : "=Q" (fprs[3]));
	asm volatile("std 5,%0" : "=Q" (fprs[5]));
	asm volatile("std 7,%0" : "=Q" (fprs[7]));
	asm volatile("std 8,%0" : "=Q" (fprs[8]));
	asm volatile("std 9,%0" : "=Q" (fprs[9]));
	asm volatile("std 10,%0" : "=Q" (fprs[10]));
	asm volatile("std 11,%0" : "=Q" (fprs[11]));
	asm volatile("std 12,%0" : "=Q" (fprs[12]));
	asm volatile("std 13,%0" : "=Q" (fprs[13]));
	asm volatile("std 14,%0" : "=Q" (fprs[14]));
	asm volatile("std 15,%0" : "=Q" (fprs[15]));
}

static inline void restore_fp_regs(freg_t *fprs)
{
	asm volatile("ld 0,%0" : : "Q" (fprs[0]));
	asm volatile("ld 2,%0" : : "Q" (fprs[2]));
	asm volatile("ld 4,%0" : : "Q" (fprs[4]));
	asm volatile("ld 6,%0" : : "Q" (fprs[6]));
	if (!MACHINE_HAS_IEEE)
		return;
	asm volatile("ld 1,%0" : : "Q" (fprs[1]));
	asm volatile("ld 3,%0" : : "Q" (fprs[3]));
	asm volatile("ld 5,%0" : : "Q" (fprs[5]));
	asm volatile("ld 7,%0" : : "Q" (fprs[7]));
	asm volatile("ld 8,%0" : : "Q" (fprs[8]));
	asm volatile("ld 9,%0" : : "Q" (fprs[9]));
	asm volatile("ld 10,%0" : : "Q" (fprs[10]));
	asm volatile("ld 11,%0" : : "Q" (fprs[11]));
	asm volatile("ld 12,%0" : : "Q" (fprs[12]));
	asm volatile("ld 13,%0" : : "Q" (fprs[13]));
	asm volatile("ld 14,%0" : : "Q" (fprs[14]));
	asm volatile("ld 15,%0" : : "Q" (fprs[15]));
104 105
}

106 107 108 109 110 111 112 113 114 115 116
static inline void save_vx_regs(__vector128 *vxrs)
{
	typedef struct { __vector128 _[__NUM_VXRS]; } addrtype;

	asm volatile(
		"	la	1,%0\n"
		"	.word	0xe70f,0x1000,0x003e\n"	/* vstm 0,15,0(1) */
		"	.word	0xe70f,0x1100,0x0c3e\n"	/* vstm 16,31,256(1) */
		: "=Q" (*(addrtype *) vxrs) : : "1");
}

117 118 119 120 121 122 123 124 125 126 127 128 129
static inline void save_vx_regs_safe(__vector128 *vxrs)
{
	unsigned long cr0, flags;

	flags = arch_local_irq_save();
	__ctl_store(cr0, 0, 0);
	__ctl_set_bit(0, 17);
	__ctl_set_bit(0, 18);
	save_vx_regs(vxrs);
	__ctl_load(cr0, 0, 0);
	arch_local_irq_restore(flags);
}

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
static inline void restore_vx_regs(__vector128 *vxrs)
{
	typedef struct { __vector128 _[__NUM_VXRS]; } addrtype;

	asm volatile(
		"	la	1,%0\n"
		"	.word	0xe70f,0x1000,0x0036\n"	/* vlm 0,15,0(1) */
		"	.word	0xe70f,0x1100,0x0c36\n"	/* vlm 16,31,256(1) */
		: : "Q" (*(addrtype *) vxrs) : "1");
}

static inline void save_fp_vx_regs(struct task_struct *task)
{
#ifdef CONFIG_64BIT
	if (task->thread.vxrs)
		save_vx_regs(task->thread.vxrs);
	else
#endif
	save_fp_regs(task->thread.fp_regs.fprs);
}

static inline void restore_fp_vx_regs(struct task_struct *task)
{
#ifdef CONFIG_64BIT
	if (task->thread.vxrs)
		restore_vx_regs(task->thread.vxrs);
	else
#endif
	restore_fp_regs(task->thread.fp_regs.fprs);
}

161 162
static inline void save_access_regs(unsigned int *acrs)
{
163 164 165
	typedef struct { int _[NUM_ACRS]; } acrstype;

	asm volatile("stam 0,15,%0" : "=Q" (*(acrstype *)acrs));
166 167 168 169
}

static inline void restore_access_regs(unsigned int *acrs)
{
170 171 172
	typedef struct { int _[NUM_ACRS]; } acrstype;

	asm volatile("lam 0,15,%0" : : "Q" (*(acrstype *)acrs));
173 174 175 176
}

#define switch_to(prev,next,last) do {					\
	if (prev->mm) {							\
177
		save_fp_ctl(&prev->thread.fp_regs.fpc);			\
178
		save_fp_vx_regs(prev);					\
179
		save_access_regs(&prev->thread.acrs[0]);		\
180
		save_ri_cb(prev->thread.ri_cb);				\
181 182
	}								\
	if (next->mm) {							\
183
		update_cr_regs(next);					\
184
		restore_fp_ctl(&next->thread.fp_regs.fpc);		\
185
		restore_fp_vx_regs(next);				\
186
		restore_access_regs(&next->thread.acrs[0]);		\
187
		restore_ri_cb(next->thread.ri_cb, prev->thread.ri_cb);	\
188 189 190 191 192
	}								\
	prev = __switch_to(prev,next);					\
} while (0)

#endif /* __ASM_SWITCH_TO_H */