1/*
2 *  arch/s390/kernel/s390fpu.c
3 *
4 *  S390 version
5 *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6 *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
7 *
8 *  s390fpu.h functions for saving & restoring the fpu state.
9 *
10 *  I couldn't inline these as linux/sched.h included half the world
11 *  & was required to at the task structure.
12 *  & the functions were too complex to make macros from.
13 *  ( & as usual I didn't feel like debugging inline code ).
14 */
15
16#include <linux/config.h>
17#include <linux/sched.h>
18
19int save_fp_regs1(s390_fp_regs *fpregs)
20{
21	int has_ieee=MACHINE_HAS_IEEE;
22/*
23  I don't think we can use STE here as this would load
24  fp registers 0 & 2 into memory locations 0 & 1 etc.
25 */
26	asm volatile ("STD   0,8(%0)\n\t"
27		      "STD   2,24(%0)\n\t"
28		      "STD   4,40(%0)\n\t"
29		      "STD   6,56(%0)"
30                      :
31		      : "a" (fpregs)
32		      : "memory"
33		);
34	if(has_ieee)
35	{
36		asm volatile ("STFPC 0(%0)\n\t"
37			      "STD   1,16(%0)\n\t"
38			      "STD   3,32(%0)\n\t"
39			      "STD   5,48(%0)\n\t"
40			      "STD   7,64(%0)\n\t"
41			      "STD   8,72(%0)\n\t"
42			      "STD   9,80(%0)\n\t"
43			      "STD   10,88(%0)\n\t"
44			      "STD   11,96(%0)\n\t"
45			      "STD   12,104(%0)\n\t"
46			      "STD   13,112(%0)\n\t"
47			      "STD   14,120(%0)\n\t"
48			      "STD   15,128(%0)\n\t"
49			      :
50			      : "a" (fpregs)
51			      : "memory"
52			);
53	}
54	return(has_ieee);
55}
56
57
58void save_fp_regs(s390_fp_regs *fpregs)
59{
60#if CONFIG_MATHEMU
61	s390_fp_regs *currentfprs;
62
63	if(!save_fp_regs1(fpregs))
64	{
65		currentfprs=&current->thread.fp_regs;
66		fpregs->fpc=currentfprs->fpc;
67		fpregs->fprs[1].d=currentfprs->fprs[1].d;
68		fpregs->fprs[3].d=currentfprs->fprs[3].d;
69		fpregs->fprs[5].d=currentfprs->fprs[5].d;
70		fpregs->fprs[7].d=currentfprs->fprs[7].d;
71		memcpy(&fpregs->fprs[8].d,&currentfprs->fprs[8].d,sizeof(freg_t)*8);
72	}
73#else
74	save_fp_regs1(fpregs);
75#endif
76}
77
78
79int restore_fp_regs1(s390_fp_regs *fpregs)
80{
81	int has_ieee=MACHINE_HAS_IEEE;
82
83	/* If we don't mask with the FPC_VALID_MASK here
84	 * we've got a very quick shutdown -h now command
85         * via a kernel specification exception.
86	 */
87	fpregs->fpc&=FPC_VALID_MASK;
88	asm volatile ("LD   0,8(%0)\n\t"
89		      "LD   2,24(%0)\n\t"
90		      "LD   4,40(%0)\n\t"
91		      "LD   6,56(%0)"
92                      :
93		      : "a" (fpregs)
94		      : "memory"
95		);
96	if(has_ieee)
97	{
98		asm volatile ("LFPC 0(%0)\n\t"
99			      "LD   1,16(%0)\n\t"
100			      "LD   3,32(%0)\n\t"
101			      "LD   5,48(%0)\n\t"
102			      "LD   7,64(%0)\n\t"
103			      "LD   8,72(%0)\n\t"
104			      "LD   9,80(%0)\n\t"
105			      "LD   10,88(%0)\n\t"
106			      "LD   11,96(%0)\n\t"
107			      "LD   12,104(%0)\n\t"
108			      "LD   13,112(%0)\n\t"
109			      "LD   14,120(%0)\n\t"
110			      "LD   15,128(%0)\n\t"
111			      :
112			      : "a" (fpregs)
113			      : "memory"
114			);
115	}
116	return(has_ieee);
117}
118
119void restore_fp_regs(s390_fp_regs *fpregs)
120{
121#if CONFIG_MATHEMU
122	s390_fp_regs *currentfprs;
123
124	if(!restore_fp_regs1(fpregs))
125	{
126		currentfprs=&current->thread.fp_regs;
127		currentfprs->fpc=fpregs->fpc;
128		currentfprs->fprs[1].d=fpregs->fprs[1].d;
129		currentfprs->fprs[3].d=fpregs->fprs[3].d;
130		currentfprs->fprs[5].d=fpregs->fprs[5].d;
131		currentfprs->fprs[7].d=fpregs->fprs[7].d;
132		memcpy(&currentfprs->fprs[8].d,&fpregs->fprs[8].d,sizeof(freg_t)*8);
133	}
134#else
135	restore_fp_regs1(fpregs);
136#endif
137}
138
139