aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/vfp
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r--arch/arm/vfp/vfpmodule.c71
1 files changed, 46 insertions, 25 deletions
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 03486be04193..2476f4c2e760 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -15,6 +15,8 @@
15#include <linux/signal.h> 15#include <linux/signal.h>
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <linux/init.h> 17#include <linux/init.h>
18
19#include <asm/thread_notify.h>
18#include <asm/vfp.h> 20#include <asm/vfp.h>
19 21
20#include "vfpinstr.h" 22#include "vfpinstr.h"
@@ -36,38 +38,55 @@ union vfp_state *last_VFP_context;
36 */ 38 */
37unsigned int VFP_arch; 39unsigned int VFP_arch;
38 40
39/* 41static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
40 * Per-thread VFP initialisation.
41 */
42void vfp_flush_thread(union vfp_state *vfp)
43{ 42{
44 memset(vfp, 0, sizeof(union vfp_state)); 43 struct thread_info *thread = v;
44 union vfp_state *vfp = &thread->vfpstate;
45 45
46 vfp->hard.fpexc = FPEXC_ENABLE; 46 switch (cmd) {
47 vfp->hard.fpscr = FPSCR_ROUND_NEAREST; 47 case THREAD_NOTIFY_FLUSH:
48 /*
49 * Per-thread VFP initialisation.
50 */
51 memset(vfp, 0, sizeof(union vfp_state));
48 52
49 /* 53 vfp->hard.fpexc = FPEXC_ENABLE;
50 * Disable VFP to ensure we initialise it first. 54 vfp->hard.fpscr = FPSCR_ROUND_NEAREST;
51 */
52 fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
53 55
54 /* 56 /*
55 * Ensure we don't try to overwrite our newly initialised 57 * Disable VFP to ensure we initialise it first.
56 * state information on the first fault. 58 */
57 */ 59 fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
58 if (last_VFP_context == vfp)
59 last_VFP_context = NULL;
60}
61 60
62/* 61 /*
63 * Per-thread VFP cleanup. 62 * FALLTHROUGH: Ensure we don't try to overwrite our newly
64 */ 63 * initialised state information on the first fault.
65void vfp_release_thread(union vfp_state *vfp) 64 */
66{ 65
67 if (last_VFP_context == vfp) 66 case THREAD_NOTIFY_RELEASE:
68 last_VFP_context = NULL; 67 /*
68 * Per-thread VFP cleanup.
69 */
70 if (last_VFP_context == vfp)
71 last_VFP_context = NULL;
72 break;
73
74 case THREAD_NOTIFY_SWITCH:
75 /*
76 * Always disable VFP so we can lazily save/restore the
77 * old state.
78 */
79 fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
80 break;
81 }
82
83 return NOTIFY_DONE;
69} 84}
70 85
86static struct notifier_block vfp_notifier_block = {
87 .notifier_call = vfp_notifier,
88};
89
71/* 90/*
72 * Raise a SIGFPE for the current process. 91 * Raise a SIGFPE for the current process.
73 * sicode describes the signal being raised. 92 * sicode describes the signal being raised.
@@ -281,6 +300,8 @@ static int __init vfp_init(void)
281 (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT, 300 (vfpsid & FPSID_VARIANT_MASK) >> FPSID_VARIANT_BIT,
282 (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT); 301 (vfpsid & FPSID_REV_MASK) >> FPSID_REV_BIT);
283 vfp_vector = vfp_support_entry; 302 vfp_vector = vfp_support_entry;
303
304 thread_register_notifier(&vfp_notifier_block);
284 } 305 }
285 return 0; 306 return 0;
286} 307}