diff options
Diffstat (limited to 'arch/sh/kernel/cpu/sh5')
-rw-r--r-- | arch/sh/kernel/cpu/sh5/Makefile | 1 | ||||
-rw-r--r-- | arch/sh/kernel/cpu/sh5/fpu.c | 170 |
2 files changed, 171 insertions, 0 deletions
diff --git a/arch/sh/kernel/cpu/sh5/Makefile b/arch/sh/kernel/cpu/sh5/Makefile index 7ea10732b5cc..6d388e8d8991 100644 --- a/arch/sh/kernel/cpu/sh5/Makefile +++ b/arch/sh/kernel/cpu/sh5/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-y := entry.o switchto.o | 1 | obj-y := entry.o switchto.o |
2 | 2 | ||
3 | obj-$(CONFIG_KALLSYMS) += unwind.o | 3 | obj-$(CONFIG_KALLSYMS) += unwind.o |
4 | obj-$(CONFIG_SH_FPU) += fpu.o | ||
diff --git a/arch/sh/kernel/cpu/sh5/fpu.c b/arch/sh/kernel/cpu/sh5/fpu.c new file mode 100644 index 000000000000..d3f5e7468dfe --- /dev/null +++ b/arch/sh/kernel/cpu/sh5/fpu.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * arch/sh64/kernel/fpu.c | ||
7 | * | ||
8 | * Copyright (C) 2001 Manuela Cirronis, Paolo Alberelli | ||
9 | * Copyright (C) 2002 STMicroelectronics Limited | ||
10 | * Author : Stuart Menefy | ||
11 | * | ||
12 | * Started from SH4 version: | ||
13 | * Copyright (C) 1999, 2000 Kaz Kojima & Niibe Yutaka | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/sched.h> | ||
18 | #include <linux/signal.h> | ||
19 | #include <asm/processor.h> | ||
20 | #include <asm/user.h> | ||
21 | #include <asm/io.h> | ||
22 | |||
23 | /* | ||
24 | * Initially load the FPU with signalling NANS. This bit pattern | ||
25 | * has the property that no matter whether considered as single or as | ||
26 | * double precision, it still represents a signalling NAN. | ||
27 | */ | ||
28 | #define sNAN64 0xFFFFFFFFFFFFFFFFULL | ||
29 | #define sNAN32 0xFFFFFFFFUL | ||
30 | |||
31 | static union sh_fpu_union init_fpuregs = { | ||
32 | .hard = { | ||
33 | .fp_regs = { [0 ... 63] = sNAN32 }, | ||
34 | .fpscr = FPSCR_INIT | ||
35 | } | ||
36 | }; | ||
37 | |||
38 | inline void fpsave(struct sh_fpu_hard_struct *fpregs) | ||
39 | { | ||
40 | asm volatile("fst.p %0, (0*8), fp0\n\t" | ||
41 | "fst.p %0, (1*8), fp2\n\t" | ||
42 | "fst.p %0, (2*8), fp4\n\t" | ||
43 | "fst.p %0, (3*8), fp6\n\t" | ||
44 | "fst.p %0, (4*8), fp8\n\t" | ||
45 | "fst.p %0, (5*8), fp10\n\t" | ||
46 | "fst.p %0, (6*8), fp12\n\t" | ||
47 | "fst.p %0, (7*8), fp14\n\t" | ||
48 | "fst.p %0, (8*8), fp16\n\t" | ||
49 | "fst.p %0, (9*8), fp18\n\t" | ||
50 | "fst.p %0, (10*8), fp20\n\t" | ||
51 | "fst.p %0, (11*8), fp22\n\t" | ||
52 | "fst.p %0, (12*8), fp24\n\t" | ||
53 | "fst.p %0, (13*8), fp26\n\t" | ||
54 | "fst.p %0, (14*8), fp28\n\t" | ||
55 | "fst.p %0, (15*8), fp30\n\t" | ||
56 | "fst.p %0, (16*8), fp32\n\t" | ||
57 | "fst.p %0, (17*8), fp34\n\t" | ||
58 | "fst.p %0, (18*8), fp36\n\t" | ||
59 | "fst.p %0, (19*8), fp38\n\t" | ||
60 | "fst.p %0, (20*8), fp40\n\t" | ||
61 | "fst.p %0, (21*8), fp42\n\t" | ||
62 | "fst.p %0, (22*8), fp44\n\t" | ||
63 | "fst.p %0, (23*8), fp46\n\t" | ||
64 | "fst.p %0, (24*8), fp48\n\t" | ||
65 | "fst.p %0, (25*8), fp50\n\t" | ||
66 | "fst.p %0, (26*8), fp52\n\t" | ||
67 | "fst.p %0, (27*8), fp54\n\t" | ||
68 | "fst.p %0, (28*8), fp56\n\t" | ||
69 | "fst.p %0, (29*8), fp58\n\t" | ||
70 | "fst.p %0, (30*8), fp60\n\t" | ||
71 | "fst.p %0, (31*8), fp62\n\t" | ||
72 | |||
73 | "fgetscr fr63\n\t" | ||
74 | "fst.s %0, (32*8), fr63\n\t" | ||
75 | : /* no output */ | ||
76 | : "r" (fpregs) | ||
77 | : "memory"); | ||
78 | } | ||
79 | |||
80 | |||
81 | static inline void | ||
82 | fpload(struct sh_fpu_hard_struct *fpregs) | ||
83 | { | ||
84 | asm volatile("fld.p %0, (0*8), fp0\n\t" | ||
85 | "fld.p %0, (1*8), fp2\n\t" | ||
86 | "fld.p %0, (2*8), fp4\n\t" | ||
87 | "fld.p %0, (3*8), fp6\n\t" | ||
88 | "fld.p %0, (4*8), fp8\n\t" | ||
89 | "fld.p %0, (5*8), fp10\n\t" | ||
90 | "fld.p %0, (6*8), fp12\n\t" | ||
91 | "fld.p %0, (7*8), fp14\n\t" | ||
92 | "fld.p %0, (8*8), fp16\n\t" | ||
93 | "fld.p %0, (9*8), fp18\n\t" | ||
94 | "fld.p %0, (10*8), fp20\n\t" | ||
95 | "fld.p %0, (11*8), fp22\n\t" | ||
96 | "fld.p %0, (12*8), fp24\n\t" | ||
97 | "fld.p %0, (13*8), fp26\n\t" | ||
98 | "fld.p %0, (14*8), fp28\n\t" | ||
99 | "fld.p %0, (15*8), fp30\n\t" | ||
100 | "fld.p %0, (16*8), fp32\n\t" | ||
101 | "fld.p %0, (17*8), fp34\n\t" | ||
102 | "fld.p %0, (18*8), fp36\n\t" | ||
103 | "fld.p %0, (19*8), fp38\n\t" | ||
104 | "fld.p %0, (20*8), fp40\n\t" | ||
105 | "fld.p %0, (21*8), fp42\n\t" | ||
106 | "fld.p %0, (22*8), fp44\n\t" | ||
107 | "fld.p %0, (23*8), fp46\n\t" | ||
108 | "fld.p %0, (24*8), fp48\n\t" | ||
109 | "fld.p %0, (25*8), fp50\n\t" | ||
110 | "fld.p %0, (26*8), fp52\n\t" | ||
111 | "fld.p %0, (27*8), fp54\n\t" | ||
112 | "fld.p %0, (28*8), fp56\n\t" | ||
113 | "fld.p %0, (29*8), fp58\n\t" | ||
114 | "fld.p %0, (30*8), fp60\n\t" | ||
115 | |||
116 | "fld.s %0, (32*8), fr63\n\t" | ||
117 | "fputscr fr63\n\t" | ||
118 | |||
119 | "fld.p %0, (31*8), fp62\n\t" | ||
120 | : /* no output */ | ||
121 | : "r" (fpregs) ); | ||
122 | } | ||
123 | |||
124 | void fpinit(struct sh_fpu_hard_struct *fpregs) | ||
125 | { | ||
126 | *fpregs = init_fpuregs.hard; | ||
127 | } | ||
128 | |||
129 | asmlinkage void | ||
130 | do_fpu_error(unsigned long ex, struct pt_regs *regs) | ||
131 | { | ||
132 | struct task_struct *tsk = current; | ||
133 | |||
134 | regs->pc += 4; | ||
135 | |||
136 | tsk->thread.trap_no = 11; | ||
137 | tsk->thread.error_code = 0; | ||
138 | force_sig(SIGFPE, tsk); | ||
139 | } | ||
140 | |||
141 | |||
142 | asmlinkage void | ||
143 | do_fpu_state_restore(unsigned long ex, struct pt_regs *regs) | ||
144 | { | ||
145 | void die(const char *str, struct pt_regs *regs, long err); | ||
146 | |||
147 | if (! user_mode(regs)) | ||
148 | die("FPU used in kernel", regs, ex); | ||
149 | |||
150 | regs->sr &= ~SR_FD; | ||
151 | |||
152 | if (last_task_used_math == current) | ||
153 | return; | ||
154 | |||
155 | enable_fpu(); | ||
156 | if (last_task_used_math != NULL) { | ||
157 | /* Other processes fpu state, save away */ | ||
158 | fpsave(&last_task_used_math->thread.fpu.hard); | ||
159 | } | ||
160 | last_task_used_math = current; | ||
161 | if (used_math()) { | ||
162 | fpload(¤t->thread.fpu.hard); | ||
163 | } else { | ||
164 | /* First time FPU user. */ | ||
165 | fpload(&init_fpuregs.hard); | ||
166 | set_used_math(); | ||
167 | } | ||
168 | disable_fpu(); | ||
169 | } | ||
170 | |||