diff options
author | Akira Takeuchi <takeuchi.akr@jp.panasonic.com> | 2010-10-27 12:28:52 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2010-10-27 12:28:52 -0400 |
commit | 278d91c4609d55202c1e63d5fc5f01466cc7bbab (patch) | |
tree | 8b0c863837508959430c1741e2e5a2d37d2890d4 /arch/mn10300/kernel | |
parent | 965ea4bbb9ae926358273368144ba838c561bc38 (diff) |
MN10300: Make the FPU operate in non-lazy mode under SMP
Make the FPU operate in non-lazy mode under SMP so that when the process that
is currently using the FPU migrates to a different CPU, we don't have to ping
its previous CPU to flush the FPU context.
Signed-off-by: Akira Takeuchi <takeuchi.akr@jp.panasonic.com>
Signed-off-by: Kiyoshi Owada <owada.kiyoshi@jp.panasonic.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'arch/mn10300/kernel')
-rw-r--r-- | arch/mn10300/kernel/Makefile | 8 | ||||
-rw-r--r-- | arch/mn10300/kernel/asm-offsets.c | 9 | ||||
-rw-r--r-- | arch/mn10300/kernel/fpu-low.S | 265 | ||||
-rw-r--r-- | arch/mn10300/kernel/fpu-nofpu-low.S | 39 | ||||
-rw-r--r-- | arch/mn10300/kernel/fpu-nofpu.c | 30 | ||||
-rw-r--r-- | arch/mn10300/kernel/fpu.c | 141 | ||||
-rw-r--r-- | arch/mn10300/kernel/traps.c | 2 |
7 files changed, 302 insertions, 192 deletions
diff --git a/arch/mn10300/kernel/Makefile b/arch/mn10300/kernel/Makefile index c4289e388071..99022351717a 100644 --- a/arch/mn10300/kernel/Makefile +++ b/arch/mn10300/kernel/Makefile | |||
@@ -3,13 +3,15 @@ | |||
3 | # | 3 | # |
4 | extra-y := head.o init_task.o vmlinux.lds | 4 | extra-y := head.o init_task.o vmlinux.lds |
5 | 5 | ||
6 | obj-y := process.o signal.o entry.o fpu.o traps.o irq.o \ | 6 | fpu-obj-y := fpu-nofpu.o fpu-nofpu-low.o |
7 | fpu-obj-$(CONFIG_FPU) := fpu.o fpu-low.o | ||
8 | |||
9 | obj-y := process.o signal.o entry.o traps.o irq.o \ | ||
7 | ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \ | 10 | ptrace.o setup.o time.o sys_mn10300.o io.o kthread.o \ |
8 | switch_to.o mn10300_ksyms.o kernel_execve.o | 11 | switch_to.o mn10300_ksyms.o kernel_execve.o $(fpu-obj-y) |
9 | 12 | ||
10 | obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o | 13 | obj-$(CONFIG_MN10300_WD_TIMER) += mn10300-watchdog.o mn10300-watchdog-low.o |
11 | 14 | ||
12 | obj-$(CONFIG_FPU) += fpu-low.o | ||
13 | 15 | ||
14 | obj-$(CONFIG_MN10300_TTYSM) += mn10300-serial.o mn10300-serial-low.o \ | 16 | obj-$(CONFIG_MN10300_TTYSM) += mn10300-serial.o mn10300-serial-low.o \ |
15 | mn10300-debug.o | 17 | mn10300-debug.o |
diff --git a/arch/mn10300/kernel/asm-offsets.c b/arch/mn10300/kernel/asm-offsets.c index 02dc7e461fef..78e290e342fc 100644 --- a/arch/mn10300/kernel/asm-offsets.c +++ b/arch/mn10300/kernel/asm-offsets.c | |||
@@ -67,6 +67,15 @@ void foo(void) | |||
67 | OFFSET(THREAD_A3, thread_struct, a3); | 67 | OFFSET(THREAD_A3, thread_struct, a3); |
68 | OFFSET(THREAD_USP, thread_struct, usp); | 68 | OFFSET(THREAD_USP, thread_struct, usp); |
69 | OFFSET(THREAD_FRAME, thread_struct, __frame); | 69 | OFFSET(THREAD_FRAME, thread_struct, __frame); |
70 | #ifdef CONFIG_FPU | ||
71 | OFFSET(THREAD_FPU_FLAGS, thread_struct, fpu_flags); | ||
72 | OFFSET(THREAD_FPU_STATE, thread_struct, fpu_state); | ||
73 | DEFINE(__THREAD_USING_FPU, THREAD_USING_FPU); | ||
74 | DEFINE(__THREAD_HAS_FPU, THREAD_HAS_FPU); | ||
75 | #endif /* CONFIG_FPU */ | ||
76 | BLANK(); | ||
77 | |||
78 | OFFSET(TASK_THREAD, task_struct, thread); | ||
70 | BLANK(); | 79 | BLANK(); |
71 | 80 | ||
72 | DEFINE(CLONE_VM_asm, CLONE_VM); | 81 | DEFINE(CLONE_VM_asm, CLONE_VM); |
diff --git a/arch/mn10300/kernel/fpu-low.S b/arch/mn10300/kernel/fpu-low.S index 96cfd47e68d5..78df25cfae29 100644 --- a/arch/mn10300/kernel/fpu-low.S +++ b/arch/mn10300/kernel/fpu-low.S | |||
@@ -8,25 +8,14 @@ | |||
8 | * as published by the Free Software Foundation; either version | 8 | * as published by the Free Software Foundation; either version |
9 | * 2 of the Licence, or (at your option) any later version. | 9 | * 2 of the Licence, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | #include <linux/linkage.h> | ||
11 | #include <asm/cpu-regs.h> | 12 | #include <asm/cpu-regs.h> |
13 | #include <asm/smp.h> | ||
14 | #include <asm/thread_info.h> | ||
15 | #include <asm/asm-offsets.h> | ||
16 | #include <asm/frame.inc> | ||
12 | 17 | ||
13 | ############################################################################### | 18 | .macro FPU_INIT_STATE_ALL |
14 | # | ||
15 | # void fpu_init_state(void) | ||
16 | # - initialise the FPU | ||
17 | # | ||
18 | ############################################################################### | ||
19 | .globl fpu_init_state | ||
20 | .type fpu_init_state,@function | ||
21 | fpu_init_state: | ||
22 | mov epsw,d0 | ||
23 | or EPSW_FE,epsw | ||
24 | |||
25 | #ifdef CONFIG_MN10300_PROC_MN103E010 | ||
26 | nop | ||
27 | nop | ||
28 | nop | ||
29 | #endif | ||
30 | fmov 0,fs0 | 19 | fmov 0,fs0 |
31 | fmov fs0,fs1 | 20 | fmov fs0,fs1 |
32 | fmov fs0,fs2 | 21 | fmov fs0,fs2 |
@@ -60,7 +49,100 @@ fpu_init_state: | |||
60 | fmov fs0,fs30 | 49 | fmov fs0,fs30 |
61 | fmov fs0,fs31 | 50 | fmov fs0,fs31 |
62 | fmov FPCR_INIT,fpcr | 51 | fmov FPCR_INIT,fpcr |
52 | .endm | ||
53 | |||
54 | .macro FPU_SAVE_ALL areg,dreg | ||
55 | fmov fs0,(\areg+) | ||
56 | fmov fs1,(\areg+) | ||
57 | fmov fs2,(\areg+) | ||
58 | fmov fs3,(\areg+) | ||
59 | fmov fs4,(\areg+) | ||
60 | fmov fs5,(\areg+) | ||
61 | fmov fs6,(\areg+) | ||
62 | fmov fs7,(\areg+) | ||
63 | fmov fs8,(\areg+) | ||
64 | fmov fs9,(\areg+) | ||
65 | fmov fs10,(\areg+) | ||
66 | fmov fs11,(\areg+) | ||
67 | fmov fs12,(\areg+) | ||
68 | fmov fs13,(\areg+) | ||
69 | fmov fs14,(\areg+) | ||
70 | fmov fs15,(\areg+) | ||
71 | fmov fs16,(\areg+) | ||
72 | fmov fs17,(\areg+) | ||
73 | fmov fs18,(\areg+) | ||
74 | fmov fs19,(\areg+) | ||
75 | fmov fs20,(\areg+) | ||
76 | fmov fs21,(\areg+) | ||
77 | fmov fs22,(\areg+) | ||
78 | fmov fs23,(\areg+) | ||
79 | fmov fs24,(\areg+) | ||
80 | fmov fs25,(\areg+) | ||
81 | fmov fs26,(\areg+) | ||
82 | fmov fs27,(\areg+) | ||
83 | fmov fs28,(\areg+) | ||
84 | fmov fs29,(\areg+) | ||
85 | fmov fs30,(\areg+) | ||
86 | fmov fs31,(\areg+) | ||
87 | fmov fpcr,\dreg | ||
88 | mov \dreg,(\areg) | ||
89 | .endm | ||
90 | |||
91 | .macro FPU_RESTORE_ALL areg,dreg | ||
92 | fmov (\areg+),fs0 | ||
93 | fmov (\areg+),fs1 | ||
94 | fmov (\areg+),fs2 | ||
95 | fmov (\areg+),fs3 | ||
96 | fmov (\areg+),fs4 | ||
97 | fmov (\areg+),fs5 | ||
98 | fmov (\areg+),fs6 | ||
99 | fmov (\areg+),fs7 | ||
100 | fmov (\areg+),fs8 | ||
101 | fmov (\areg+),fs9 | ||
102 | fmov (\areg+),fs10 | ||
103 | fmov (\areg+),fs11 | ||
104 | fmov (\areg+),fs12 | ||
105 | fmov (\areg+),fs13 | ||
106 | fmov (\areg+),fs14 | ||
107 | fmov (\areg+),fs15 | ||
108 | fmov (\areg+),fs16 | ||
109 | fmov (\areg+),fs17 | ||
110 | fmov (\areg+),fs18 | ||
111 | fmov (\areg+),fs19 | ||
112 | fmov (\areg+),fs20 | ||
113 | fmov (\areg+),fs21 | ||
114 | fmov (\areg+),fs22 | ||
115 | fmov (\areg+),fs23 | ||
116 | fmov (\areg+),fs24 | ||
117 | fmov (\areg+),fs25 | ||
118 | fmov (\areg+),fs26 | ||
119 | fmov (\areg+),fs27 | ||
120 | fmov (\areg+),fs28 | ||
121 | fmov (\areg+),fs29 | ||
122 | fmov (\areg+),fs30 | ||
123 | fmov (\areg+),fs31 | ||
124 | mov (\areg),\dreg | ||
125 | fmov \dreg,fpcr | ||
126 | .endm | ||
63 | 127 | ||
128 | ############################################################################### | ||
129 | # | ||
130 | # void fpu_init_state(void) | ||
131 | # - initialise the FPU | ||
132 | # | ||
133 | ############################################################################### | ||
134 | .globl fpu_init_state | ||
135 | .type fpu_init_state,@function | ||
136 | fpu_init_state: | ||
137 | mov epsw,d0 | ||
138 | or EPSW_FE,epsw | ||
139 | |||
140 | #ifdef CONFIG_MN10300_PROC_MN103E010 | ||
141 | nop | ||
142 | nop | ||
143 | nop | ||
144 | #endif | ||
145 | FPU_INIT_STATE_ALL | ||
64 | #ifdef CONFIG_MN10300_PROC_MN103E010 | 146 | #ifdef CONFIG_MN10300_PROC_MN103E010 |
65 | nop | 147 | nop |
66 | nop | 148 | nop |
@@ -89,40 +171,7 @@ fpu_save: | |||
89 | nop | 171 | nop |
90 | #endif | 172 | #endif |
91 | mov d0,a0 | 173 | mov d0,a0 |
92 | fmov fs0,(a0+) | 174 | FPU_SAVE_ALL a0,d0 |
93 | fmov fs1,(a0+) | ||
94 | fmov fs2,(a0+) | ||
95 | fmov fs3,(a0+) | ||
96 | fmov fs4,(a0+) | ||
97 | fmov fs5,(a0+) | ||
98 | fmov fs6,(a0+) | ||
99 | fmov fs7,(a0+) | ||
100 | fmov fs8,(a0+) | ||
101 | fmov fs9,(a0+) | ||
102 | fmov fs10,(a0+) | ||
103 | fmov fs11,(a0+) | ||
104 | fmov fs12,(a0+) | ||
105 | fmov fs13,(a0+) | ||
106 | fmov fs14,(a0+) | ||
107 | fmov fs15,(a0+) | ||
108 | fmov fs16,(a0+) | ||
109 | fmov fs17,(a0+) | ||
110 | fmov fs18,(a0+) | ||
111 | fmov fs19,(a0+) | ||
112 | fmov fs20,(a0+) | ||
113 | fmov fs21,(a0+) | ||
114 | fmov fs22,(a0+) | ||
115 | fmov fs23,(a0+) | ||
116 | fmov fs24,(a0+) | ||
117 | fmov fs25,(a0+) | ||
118 | fmov fs26,(a0+) | ||
119 | fmov fs27,(a0+) | ||
120 | fmov fs28,(a0+) | ||
121 | fmov fs29,(a0+) | ||
122 | fmov fs30,(a0+) | ||
123 | fmov fs31,(a0+) | ||
124 | fmov fpcr,d0 | ||
125 | mov d0,(a0) | ||
126 | #ifdef CONFIG_MN10300_PROC_MN103E010 | 175 | #ifdef CONFIG_MN10300_PROC_MN103E010 |
127 | nop | 176 | nop |
128 | nop | 177 | nop |
@@ -135,63 +184,75 @@ fpu_save: | |||
135 | 184 | ||
136 | ############################################################################### | 185 | ############################################################################### |
137 | # | 186 | # |
138 | # void fpu_restore(struct fpu_state_struct *) | 187 | # void fpu_disabled(void) |
139 | # - restore the fpu state | 188 | # - handle an exception due to the FPU being disabled |
140 | # - note that an FPU Operational exception might occur during this process | 189 | # when CONFIG_FPU is enabled |
141 | # | 190 | # |
142 | ############################################################################### | 191 | ############################################################################### |
143 | .globl fpu_restore | 192 | .type fpu_disabled,@function |
144 | .type fpu_restore,@function | 193 | .globl fpu_disabled |
145 | fpu_restore: | 194 | fpu_disabled: |
146 | mov epsw,d1 | 195 | or EPSW_nAR|EPSW_FE,epsw |
147 | or EPSW_FE,epsw /* enable the FPU so we can access it */ | ||
148 | |||
149 | #ifdef CONFIG_MN10300_PROC_MN103E010 | ||
150 | nop | 196 | nop |
151 | nop | 197 | nop |
152 | #endif | ||
153 | mov d0,a0 | ||
154 | fmov (a0+),fs0 | ||
155 | fmov (a0+),fs1 | ||
156 | fmov (a0+),fs2 | ||
157 | fmov (a0+),fs3 | ||
158 | fmov (a0+),fs4 | ||
159 | fmov (a0+),fs5 | ||
160 | fmov (a0+),fs6 | ||
161 | fmov (a0+),fs7 | ||
162 | fmov (a0+),fs8 | ||
163 | fmov (a0+),fs9 | ||
164 | fmov (a0+),fs10 | ||
165 | fmov (a0+),fs11 | ||
166 | fmov (a0+),fs12 | ||
167 | fmov (a0+),fs13 | ||
168 | fmov (a0+),fs14 | ||
169 | fmov (a0+),fs15 | ||
170 | fmov (a0+),fs16 | ||
171 | fmov (a0+),fs17 | ||
172 | fmov (a0+),fs18 | ||
173 | fmov (a0+),fs19 | ||
174 | fmov (a0+),fs20 | ||
175 | fmov (a0+),fs21 | ||
176 | fmov (a0+),fs22 | ||
177 | fmov (a0+),fs23 | ||
178 | fmov (a0+),fs24 | ||
179 | fmov (a0+),fs25 | ||
180 | fmov (a0+),fs26 | ||
181 | fmov (a0+),fs27 | ||
182 | fmov (a0+),fs28 | ||
183 | fmov (a0+),fs29 | ||
184 | fmov (a0+),fs30 | ||
185 | fmov (a0+),fs31 | ||
186 | mov (a0),d0 | ||
187 | fmov d0,fpcr | ||
188 | #ifdef CONFIG_MN10300_PROC_MN103E010 | ||
189 | nop | 198 | nop |
199 | |||
200 | mov sp,a1 | ||
201 | mov (a1),d1 /* get epsw of user context */ | ||
202 | and ~(THREAD_SIZE-1),a1 /* a1: (thread_info *ti) */ | ||
203 | mov (TI_task,a1),a2 /* a2: (task_struct *tsk) */ | ||
204 | btst EPSW_nSL,d1 | ||
205 | beq fpu_used_in_kernel | ||
206 | |||
207 | or EPSW_FE,d1 | ||
208 | mov d1,(sp) | ||
209 | mov (TASK_THREAD+THREAD_FPU_FLAGS,a2),d1 | ||
210 | #ifndef CONFIG_LAZY_SAVE_FPU | ||
211 | or __THREAD_HAS_FPU,d1 | ||
212 | mov d1,(TASK_THREAD+THREAD_FPU_FLAGS,a2) | ||
213 | #else /* !CONFIG_LAZY_SAVE_FPU */ | ||
214 | mov (fpu_state_owner),a0 | ||
215 | cmp 0,a0 | ||
216 | beq fpu_regs_save_end | ||
217 | |||
218 | mov (TASK_THREAD+THREAD_UREGS,a0),a1 | ||
219 | add TASK_THREAD+THREAD_FPU_STATE,a0 | ||
220 | FPU_SAVE_ALL a0,d0 | ||
221 | |||
222 | mov (REG_EPSW,a1),d0 | ||
223 | and ~EPSW_FE,d0 | ||
224 | mov d0,(REG_EPSW,a1) | ||
225 | |||
226 | fpu_regs_save_end: | ||
227 | mov a2,(fpu_state_owner) | ||
228 | #endif /* !CONFIG_LAZY_SAVE_FPU */ | ||
229 | |||
230 | btst __THREAD_USING_FPU,d1 | ||
231 | beq fpu_regs_init | ||
232 | add TASK_THREAD+THREAD_FPU_STATE,a2 | ||
233 | FPU_RESTORE_ALL a2,d0 | ||
234 | rti | ||
235 | |||
236 | fpu_regs_init: | ||
237 | FPU_INIT_STATE_ALL | ||
238 | add TASK_THREAD+THREAD_FPU_FLAGS,a2 | ||
239 | bset __THREAD_USING_FPU,(0,a2) | ||
240 | rti | ||
241 | |||
242 | fpu_used_in_kernel: | ||
243 | and ~(EPSW_nAR|EPSW_FE),epsw | ||
190 | nop | 244 | nop |
191 | nop | 245 | nop |
192 | #endif | ||
193 | 246 | ||
194 | mov d1,epsw | 247 | add -4,sp |
195 | ret [],0 | 248 | SAVE_ALL |
249 | mov -1,d0 | ||
250 | mov d0,(REG_ORIG_D0,fp) | ||
251 | |||
252 | and ~EPSW_NMID,epsw | ||
253 | |||
254 | mov fp,d0 | ||
255 | call fpu_disabled_in_kernel[],0 | ||
256 | jmp ret_from_exception | ||
196 | 257 | ||
197 | .size fpu_restore,.-fpu_restore | 258 | .size fpu_disabled,.-fpu_disabled |
diff --git a/arch/mn10300/kernel/fpu-nofpu-low.S b/arch/mn10300/kernel/fpu-nofpu-low.S new file mode 100644 index 000000000000..7ea087a549f4 --- /dev/null +++ b/arch/mn10300/kernel/fpu-nofpu-low.S | |||
@@ -0,0 +1,39 @@ | |||
1 | /* MN10300 Low level FPU management operations | ||
2 | * | ||
3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | #include <linux/linkage.h> | ||
12 | #include <asm/cpu-regs.h> | ||
13 | #include <asm/smp.h> | ||
14 | #include <asm/thread_info.h> | ||
15 | #include <asm/asm-offsets.h> | ||
16 | #include <asm/frame.inc> | ||
17 | |||
18 | ############################################################################### | ||
19 | # | ||
20 | # void fpu_disabled(void) | ||
21 | # - handle an exception due to the FPU being disabled | ||
22 | # when CONFIG_FPU is disabled | ||
23 | # | ||
24 | ############################################################################### | ||
25 | .type fpu_disabled,@function | ||
26 | .globl fpu_disabled | ||
27 | fpu_disabled: | ||
28 | add -4,sp | ||
29 | SAVE_ALL | ||
30 | mov -1,d0 | ||
31 | mov d0,(REG_ORIG_D0,fp) | ||
32 | |||
33 | and ~EPSW_NMID,epsw | ||
34 | |||
35 | mov fp,d0 | ||
36 | call unexpected_fpu_exception[],0 | ||
37 | jmp ret_from_exception | ||
38 | |||
39 | .size fpu_disabled,.-fpu_disabled | ||
diff --git a/arch/mn10300/kernel/fpu-nofpu.c b/arch/mn10300/kernel/fpu-nofpu.c new file mode 100644 index 000000000000..31c765b92c5d --- /dev/null +++ b/arch/mn10300/kernel/fpu-nofpu.c | |||
@@ -0,0 +1,30 @@ | |||
1 | /* MN10300 FPU management | ||
2 | * | ||
3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public Licence | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the Licence, or (at your option) any later version. | ||
10 | */ | ||
11 | #include <asm/fpu.h> | ||
12 | |||
13 | /* | ||
14 | * handle an FPU operational exception | ||
15 | * - there's a possibility that if the FPU is asynchronous, the signal might | ||
16 | * be meant for a process other than the current one | ||
17 | */ | ||
18 | asmlinkage | ||
19 | void unexpected_fpu_exception(struct pt_regs *regs, enum exception_code code) | ||
20 | { | ||
21 | panic("An FPU exception was received, but there's no FPU enabled."); | ||
22 | } | ||
23 | |||
24 | /* | ||
25 | * fill in the FPU structure for a core dump | ||
26 | */ | ||
27 | int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpreg) | ||
28 | { | ||
29 | return 0; /* not valid */ | ||
30 | } | ||
diff --git a/arch/mn10300/kernel/fpu.c b/arch/mn10300/kernel/fpu.c index e705f25ad5ff..5f9c3fa19a85 100644 --- a/arch/mn10300/kernel/fpu.c +++ b/arch/mn10300/kernel/fpu.c | |||
@@ -12,56 +12,19 @@ | |||
12 | #include <asm/fpu.h> | 12 | #include <asm/fpu.h> |
13 | #include <asm/elf.h> | 13 | #include <asm/elf.h> |
14 | #include <asm/exceptions.h> | 14 | #include <asm/exceptions.h> |
15 | #include <asm/system.h> | ||
15 | 16 | ||
17 | #ifdef CONFIG_LAZY_SAVE_FPU | ||
16 | struct task_struct *fpu_state_owner; | 18 | struct task_struct *fpu_state_owner; |
19 | #endif | ||
17 | 20 | ||
18 | /* | 21 | /* |
19 | * handle an exception due to the FPU being disabled | 22 | * error functions in FPU disabled exception |
20 | */ | 23 | */ |
21 | asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code) | 24 | asmlinkage void fpu_disabled_in_kernel(struct pt_regs *regs) |
22 | { | 25 | { |
23 | struct task_struct *tsk = current; | 26 | die_if_no_fixup("An FPU Disabled exception happened in kernel space\n", |
24 | 27 | regs, EXCEP_FPU_DISABLED); | |
25 | if (!user_mode(regs)) | ||
26 | die_if_no_fixup("An FPU Disabled exception happened in" | ||
27 | " kernel space\n", | ||
28 | regs, code); | ||
29 | |||
30 | #ifdef CONFIG_FPU | ||
31 | preempt_disable(); | ||
32 | |||
33 | /* transfer the last process's FPU state to memory */ | ||
34 | if (fpu_state_owner) { | ||
35 | fpu_save(&fpu_state_owner->thread.fpu_state); | ||
36 | fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE; | ||
37 | } | ||
38 | |||
39 | /* the current process now owns the FPU state */ | ||
40 | fpu_state_owner = tsk; | ||
41 | regs->epsw |= EPSW_FE; | ||
42 | |||
43 | /* load the FPU with the current process's FPU state or invent a new | ||
44 | * clean one if the process doesn't have one */ | ||
45 | if (is_using_fpu(tsk)) { | ||
46 | fpu_restore(&tsk->thread.fpu_state); | ||
47 | } else { | ||
48 | fpu_init_state(); | ||
49 | set_using_fpu(tsk); | ||
50 | } | ||
51 | |||
52 | preempt_enable(); | ||
53 | #else | ||
54 | { | ||
55 | siginfo_t info; | ||
56 | |||
57 | info.si_signo = SIGFPE; | ||
58 | info.si_errno = 0; | ||
59 | info.si_addr = (void *) tsk->thread.uregs->pc; | ||
60 | info.si_code = FPE_FLTINV; | ||
61 | |||
62 | force_sig_info(SIGFPE, &info, tsk); | ||
63 | } | ||
64 | #endif /* CONFIG_FPU */ | ||
65 | } | 28 | } |
66 | 29 | ||
67 | /* | 30 | /* |
@@ -71,15 +34,16 @@ asmlinkage void fpu_disabled(struct pt_regs *regs, enum exception_code code) | |||
71 | */ | 34 | */ |
72 | asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code) | 35 | asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code) |
73 | { | 36 | { |
74 | struct task_struct *tsk = fpu_state_owner; | 37 | struct task_struct *tsk = current; |
75 | siginfo_t info; | 38 | siginfo_t info; |
39 | u32 fpcr; | ||
76 | 40 | ||
77 | if (!user_mode(regs)) | 41 | if (!user_mode(regs)) |
78 | die_if_no_fixup("An FPU Operation exception happened in" | 42 | die_if_no_fixup("An FPU Operation exception happened in" |
79 | " kernel space\n", | 43 | " kernel space\n", |
80 | regs, code); | 44 | regs, code); |
81 | 45 | ||
82 | if (!tsk) | 46 | if (!is_using_fpu(tsk)) |
83 | die_if_no_fixup("An FPU Operation exception happened," | 47 | die_if_no_fixup("An FPU Operation exception happened," |
84 | " but the FPU is not in use", | 48 | " but the FPU is not in use", |
85 | regs, code); | 49 | regs, code); |
@@ -89,48 +53,45 @@ asmlinkage void fpu_exception(struct pt_regs *regs, enum exception_code code) | |||
89 | info.si_addr = (void *) tsk->thread.uregs->pc; | 53 | info.si_addr = (void *) tsk->thread.uregs->pc; |
90 | info.si_code = FPE_FLTINV; | 54 | info.si_code = FPE_FLTINV; |
91 | 55 | ||
92 | #ifdef CONFIG_FPU | 56 | unlazy_fpu(tsk); |
93 | { | ||
94 | u32 fpcr; | ||
95 | 57 | ||
96 | /* get FPCR (we need to enable the FPU whilst we do this) */ | 58 | fpcr = tsk->thread.fpu_state.fpcr; |
97 | asm volatile(" or %1,epsw \n" | 59 | |
98 | #ifdef CONFIG_MN10300_PROC_MN103E010 | 60 | if (fpcr & FPCR_EC_Z) |
99 | " nop \n" | 61 | info.si_code = FPE_FLTDIV; |
100 | " nop \n" | 62 | else if (fpcr & FPCR_EC_O) |
101 | " nop \n" | 63 | info.si_code = FPE_FLTOVF; |
102 | #endif | 64 | else if (fpcr & FPCR_EC_U) |
103 | " fmov fpcr,%0 \n" | 65 | info.si_code = FPE_FLTUND; |
104 | #ifdef CONFIG_MN10300_PROC_MN103E010 | 66 | else if (fpcr & FPCR_EC_I) |
105 | " nop \n" | 67 | info.si_code = FPE_FLTRES; |
106 | " nop \n" | ||
107 | " nop \n" | ||
108 | #endif | ||
109 | " and %2,epsw \n" | ||
110 | : "=&d"(fpcr) | ||
111 | : "i"(EPSW_FE), "i"(~EPSW_FE) | ||
112 | ); | ||
113 | |||
114 | if (fpcr & FPCR_EC_Z) | ||
115 | info.si_code = FPE_FLTDIV; | ||
116 | else if (fpcr & FPCR_EC_O) | ||
117 | info.si_code = FPE_FLTOVF; | ||
118 | else if (fpcr & FPCR_EC_U) | ||
119 | info.si_code = FPE_FLTUND; | ||
120 | else if (fpcr & FPCR_EC_I) | ||
121 | info.si_code = FPE_FLTRES; | ||
122 | } | ||
123 | #endif | ||
124 | 68 | ||
125 | force_sig_info(SIGFPE, &info, tsk); | 69 | force_sig_info(SIGFPE, &info, tsk); |
126 | } | 70 | } |
127 | 71 | ||
128 | /* | 72 | /* |
73 | * handle an FPU invalid_op exception | ||
74 | * - Derived from DO_EINFO() macro in arch/mn10300/kernel/traps.c | ||
75 | */ | ||
76 | asmlinkage void fpu_invalid_op(struct pt_regs *regs, enum exception_code code) | ||
77 | { | ||
78 | siginfo_t info; | ||
79 | |||
80 | if (!user_mode(regs)) | ||
81 | die_if_no_fixup("FPU invalid opcode", regs, code); | ||
82 | |||
83 | info.si_signo = SIGILL; | ||
84 | info.si_errno = 0; | ||
85 | info.si_code = ILL_COPROC; | ||
86 | info.si_addr = (void *) regs->pc; | ||
87 | force_sig_info(info.si_signo, &info, current); | ||
88 | } | ||
89 | |||
90 | /* | ||
129 | * save the FPU state to a signal context | 91 | * save the FPU state to a signal context |
130 | */ | 92 | */ |
131 | int fpu_setup_sigcontext(struct fpucontext *fpucontext) | 93 | int fpu_setup_sigcontext(struct fpucontext *fpucontext) |
132 | { | 94 | { |
133 | #ifdef CONFIG_FPU | ||
134 | struct task_struct *tsk = current; | 95 | struct task_struct *tsk = current; |
135 | 96 | ||
136 | if (!is_using_fpu(tsk)) | 97 | if (!is_using_fpu(tsk)) |
@@ -142,11 +103,19 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext) | |||
142 | */ | 103 | */ |
143 | preempt_disable(); | 104 | preempt_disable(); |
144 | 105 | ||
106 | #ifndef CONFIG_LAZY_SAVE_FPU | ||
107 | if (tsk->thread.fpu_flags & THREAD_HAS_FPU) { | ||
108 | fpu_save(&tsk->thread.fpu_state); | ||
109 | tsk->thread.uregs->epsw &= ~EPSW_FE; | ||
110 | tsk->thread.fpu_flags &= ~THREAD_HAS_FPU; | ||
111 | } | ||
112 | #else /* !CONFIG_LAZY_SAVE_FPU */ | ||
145 | if (fpu_state_owner == tsk) { | 113 | if (fpu_state_owner == tsk) { |
146 | fpu_save(&tsk->thread.fpu_state); | 114 | fpu_save(&tsk->thread.fpu_state); |
147 | fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE; | 115 | fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE; |
148 | fpu_state_owner = NULL; | 116 | fpu_state_owner = NULL; |
149 | } | 117 | } |
118 | #endif /* !CONFIG_LAZY_SAVE_FPU */ | ||
150 | 119 | ||
151 | preempt_enable(); | 120 | preempt_enable(); |
152 | 121 | ||
@@ -161,9 +130,6 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext) | |||
161 | return -1; | 130 | return -1; |
162 | 131 | ||
163 | return 1; | 132 | return 1; |
164 | #else | ||
165 | return 0; | ||
166 | #endif | ||
167 | } | 133 | } |
168 | 134 | ||
169 | /* | 135 | /* |
@@ -171,17 +137,23 @@ int fpu_setup_sigcontext(struct fpucontext *fpucontext) | |||
171 | */ | 137 | */ |
172 | void fpu_kill_state(struct task_struct *tsk) | 138 | void fpu_kill_state(struct task_struct *tsk) |
173 | { | 139 | { |
174 | #ifdef CONFIG_FPU | ||
175 | /* disown anything left in the FPU */ | 140 | /* disown anything left in the FPU */ |
176 | preempt_disable(); | 141 | preempt_disable(); |
177 | 142 | ||
143 | #ifndef CONFIG_LAZY_SAVE_FPU | ||
144 | if (tsk->thread.fpu_flags & THREAD_HAS_FPU) { | ||
145 | tsk->thread.uregs->epsw &= ~EPSW_FE; | ||
146 | tsk->thread.fpu_flags &= ~THREAD_HAS_FPU; | ||
147 | } | ||
148 | #else /* !CONFIG_LAZY_SAVE_FPU */ | ||
178 | if (fpu_state_owner == tsk) { | 149 | if (fpu_state_owner == tsk) { |
179 | fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE; | 150 | fpu_state_owner->thread.uregs->epsw &= ~EPSW_FE; |
180 | fpu_state_owner = NULL; | 151 | fpu_state_owner = NULL; |
181 | } | 152 | } |
153 | #endif /* !CONFIG_LAZY_SAVE_FPU */ | ||
182 | 154 | ||
183 | preempt_enable(); | 155 | preempt_enable(); |
184 | #endif | 156 | |
185 | /* we no longer have a valid current FPU state */ | 157 | /* we no longer have a valid current FPU state */ |
186 | clear_using_fpu(tsk); | 158 | clear_using_fpu(tsk); |
187 | } | 159 | } |
@@ -195,8 +167,7 @@ int fpu_restore_sigcontext(struct fpucontext *fpucontext) | |||
195 | int ret; | 167 | int ret; |
196 | 168 | ||
197 | /* load up the old FPU state */ | 169 | /* load up the old FPU state */ |
198 | ret = copy_from_user(&tsk->thread.fpu_state, | 170 | ret = copy_from_user(&tsk->thread.fpu_state, fpucontext, |
199 | fpucontext, | ||
200 | min(sizeof(struct fpu_state_struct), | 171 | min(sizeof(struct fpu_state_struct), |
201 | sizeof(struct fpucontext))); | 172 | sizeof(struct fpucontext))); |
202 | if (!ret) | 173 | if (!ret) |
diff --git a/arch/mn10300/kernel/traps.c b/arch/mn10300/kernel/traps.c index c7257a1304a9..716a221df2f9 100644 --- a/arch/mn10300/kernel/traps.c +++ b/arch/mn10300/kernel/traps.c | |||
@@ -101,7 +101,6 @@ DO_EINFO(SIGILL, {}, "invalid opcode", invalid_op, ILL_ILLOPC); | |||
101 | DO_EINFO(SIGILL, {}, "invalid ex opcode", invalid_exop, ILL_ILLOPC); | 101 | DO_EINFO(SIGILL, {}, "invalid ex opcode", invalid_exop, ILL_ILLOPC); |
102 | DO_EINFO(SIGBUS, {}, "invalid address", mem_error, BUS_ADRERR); | 102 | DO_EINFO(SIGBUS, {}, "invalid address", mem_error, BUS_ADRERR); |
103 | DO_EINFO(SIGBUS, {}, "bus error", bus_error, BUS_ADRERR); | 103 | DO_EINFO(SIGBUS, {}, "bus error", bus_error, BUS_ADRERR); |
104 | DO_EINFO(SIGILL, {}, "FPU invalid opcode", fpu_invalid_op, ILL_COPROC); | ||
105 | 104 | ||
106 | DO_ERROR(SIGTRAP, | 105 | DO_ERROR(SIGTRAP, |
107 | #ifndef CONFIG_MN10300_USING_JTAG | 106 | #ifndef CONFIG_MN10300_USING_JTAG |
@@ -561,7 +560,6 @@ void __init trap_init(void) | |||
561 | set_excp_vector(EXCEP_PRIVINSACC, insn_acc_error); | 560 | set_excp_vector(EXCEP_PRIVINSACC, insn_acc_error); |
562 | set_excp_vector(EXCEP_PRIVDATACC, data_acc_error); | 561 | set_excp_vector(EXCEP_PRIVDATACC, data_acc_error); |
563 | set_excp_vector(EXCEP_DATINSACC, insn_acc_error); | 562 | set_excp_vector(EXCEP_DATINSACC, insn_acc_error); |
564 | set_excp_vector(EXCEP_FPU_DISABLED, fpu_disabled); | ||
565 | set_excp_vector(EXCEP_FPU_UNIMPINS, fpu_invalid_op); | 563 | set_excp_vector(EXCEP_FPU_UNIMPINS, fpu_invalid_op); |
566 | set_excp_vector(EXCEP_FPU_OPERATION, fpu_exception); | 564 | set_excp_vector(EXCEP_FPU_OPERATION, fpu_exception); |
567 | 565 | ||