summaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/s390fpu.c
blob: c56c50d6617a1053cf84836cb6daae5b8b9a5d51 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
/*
 *  arch/s390/kernel/s390fpu.c
 *
 *  S390 version
 *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
 *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
 *
 *  s390fpu.h functions for saving & restoring the fpu state.
 *
 *  I couldn't inline these as linux/sched.h included half the world
 *  & was required to at the task structure.
 *  & the functions were too complex to make macros from.
 *  ( & as usual I didn't feel like debugging inline code ).
 */

#include <linux/config.h>
#include <linux/sched.h>

int save_fp_regs1(s390_fp_regs *fpregs)
{
	int has_ieee=MACHINE_HAS_IEEE;
/*
  I don't think we can use STE here as this would load
  fp registers 0 & 2 into memory locations 0 & 1 etc. 
 */	
	asm volatile ("STD   0,8(%0)\n\t"
		      "STD   2,24(%0)\n\t"
		      "STD   4,40(%0)\n\t"
		      "STD   6,56(%0)"
                      : 
		      : "a" (fpregs)
		      : "memory"
		);
	if(has_ieee)
	{
		asm volatile ("STFPC 0(%0)\n\t"
			      "STD   1,16(%0)\n\t"
			      "STD   3,32(%0)\n\t"
			      "STD   5,48(%0)\n\t"
			      "STD   7,64(%0)\n\t"
			      "STD   8,72(%0)\n\t"
			      "STD   9,80(%0)\n\t"
			      "STD   10,88(%0)\n\t"
			      "STD   11,96(%0)\n\t"
			      "STD   12,104(%0)\n\t"
			      "STD   13,112(%0)\n\t"
			      "STD   14,120(%0)\n\t"
			      "STD   15,128(%0)\n\t"
			      : 
			      : "a" (fpregs)
			      : "memory"
			);
	}
	return(has_ieee);
}


void save_fp_regs(s390_fp_regs *fpregs)
{
#if CONFIG_IEEEFPU_EMULATION
	s390_fp_regs *currentfprs;
#endif
#if CONFIG_IEEEFPU_EMULATION
	if(!save_fp_regs1(fpregs))
	{
		currentfprs=&current->thread.fp_regs;
		fpregs->fpc=currentfprs->fpc;
		fpregs->fprs[1].d=currentfprs->fprs[1].d;
		fpregs->fprs[3].d=currentfprs->fprs[3].d;
		fpregs->fprs[5].d=currentfprs->fprs[5].d;
		fpregs->fprs[7].d=currentfprs->fprs[7].d;
		memcpy(&fpregs->fprs[8].d,&currentfprs->fprs[8].d,sizeof(freg_t)*8);
	}
#else
	save_fp_regs1(fpregs);
#endif
}


int restore_fp_regs1(s390_fp_regs *fpregs)
{
	int has_ieee=MACHINE_HAS_IEEE;

	/* If we don't mask with the FPC_VALID_MASK here
	 * we've got a very quick shutdown -h now command
         * via a kernel specification exception.
	 */
	fpregs->fpc&=FPC_VALID_MASK;
	asm volatile ("LD   0,8(%0)\n\t"
		      "LD   2,24(%0)\n\t"
		      "LD   4,40(%0)\n\t"
		      "LD   6,56(%0)"
                      : 
		      : "a" (fpregs)
		      : "memory"
		);
	if(has_ieee)
	{
		asm volatile ("LFPC 0(%0)\n\t"
			      "LD   1,16(%0)\n\t"
			      "LD   3,32(%0)\n\t"
			      "LD   5,48(%0)\n\t"
			      "LD   7,64(%0)\n\t"
			      "LD   8,72(%0)\n\t"
			      "LD   9,80(%0)\n\t"
			      "LD   10,88(%0)\n\t"
			      "LD   11,96(%0)\n\t"
			      "LD   12,104(%0)\n\t"
			      "LD   13,112(%0)\n\t"
			      "LD   14,120(%0)\n\t"
			      "LD   15,128(%0)\n\t"
			      : 
			      : "a" (fpregs)
			      : "memory"
			);
	}
	return(has_ieee);
}

void restore_fp_regs(s390_fp_regs *fpregs)
{
#if CONFIG_IEEEFPU_EMULATION
	s390_fp_regs *currentfprs;
#endif

#if CONFIG_IEEEFPU_EMULATION
	if(!restore_fp_regs1(fpregs))
	{
		currentfprs=&current->thread.fp_regs;
		currentfprs->fpc=fpregs->fpc;
		currentfprs->fprs[1].d=fpregs->fprs[1].d;
		currentfprs->fprs[3].d=fpregs->fprs[3].d;
		currentfprs->fprs[5].d=fpregs->fprs[5].d;
		currentfprs->fprs[7].d=fpregs->fprs[7].d;
		memcpy(&currentfprs->fprs[8].d,&fpregs->fprs[8].d,sizeof(freg_t)*8);
	}
#else
	restore_fp_regs1(fpregs);
#endif
}