diff options
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r-- | arch/arm/vfp/vfpmodule.c | 71 |
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 | */ |
37 | unsigned int VFP_arch; | 39 | unsigned int VFP_arch; |
38 | 40 | ||
39 | /* | 41 | static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) |
40 | * Per-thread VFP initialisation. | ||
41 | */ | ||
42 | void 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. |
65 | void 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 | ||
86 | static 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 | } |