aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/vfp
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/arm/vfp
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'arch/arm/vfp')
-rw-r--r--arch/arm/vfp/Makefile4
-rw-r--r--arch/arm/vfp/vfphw.S1
-rw-r--r--arch/arm/vfp/vfpmodule.c82
3 files changed, 62 insertions, 25 deletions
diff --git a/arch/arm/vfp/Makefile b/arch/arm/vfp/Makefile
index 39f6d8e1af73..6de73aab0195 100644
--- a/arch/arm/vfp/Makefile
+++ b/arch/arm/vfp/Makefile
@@ -4,8 +4,8 @@
4# Copyright (C) 2001 ARM Limited 4# Copyright (C) 2001 ARM Limited
5# 5#
6 6
7# EXTRA_CFLAGS := -DDEBUG 7# ccflags-y := -DDEBUG
8# EXTRA_AFLAGS := -DDEBUG 8# asflags-y := -DDEBUG
9 9
10KBUILD_AFLAGS :=$(KBUILD_AFLAGS:-msoft-float=-Wa,-mfpu=softvfp+vfp) 10KBUILD_AFLAGS :=$(KBUILD_AFLAGS:-msoft-float=-Wa,-mfpu=softvfp+vfp)
11LDFLAGS +=--no-warn-mismatch 11LDFLAGS +=--no-warn-mismatch
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index d66cead97d28..9897dcfc16d6 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -206,6 +206,7 @@ ENTRY(vfp_save_state)
206 mov pc, lr 206 mov pc, lr
207ENDPROC(vfp_save_state) 207ENDPROC(vfp_save_state)
208 208
209 .align
209last_VFP_context_address: 210last_VFP_context_address:
210 .word last_VFP_context 211 .word last_VFP_context
211 212
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 8063a322c790..f25e7ec89416 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -10,9 +10,12 @@
10 */ 10 */
11#include <linux/module.h> 11#include <linux/module.h>
12#include <linux/types.h> 12#include <linux/types.h>
13#include <linux/cpu.h>
13#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/notifier.h>
14#include <linux/signal.h> 16#include <linux/signal.h>
15#include <linux/sched.h> 17#include <linux/sched.h>
18#include <linux/smp.h>
16#include <linux/init.h> 19#include <linux/init.h>
17 20
18#include <asm/cputype.h> 21#include <asm/cputype.h>
@@ -75,6 +78,14 @@ static void vfp_thread_exit(struct thread_info *thread)
75 put_cpu(); 78 put_cpu();
76} 79}
77 80
81static void vfp_thread_copy(struct thread_info *thread)
82{
83 struct thread_info *parent = current_thread_info();
84
85 vfp_sync_hwstate(parent);
86 thread->vfpstate = parent->vfpstate;
87}
88
78/* 89/*
79 * When this function is called with the following 'cmd's, the following 90 * When this function is called with the following 'cmd's, the following
80 * is true while this function is being run: 91 * is true while this function is being run:
@@ -101,12 +112,17 @@ static void vfp_thread_exit(struct thread_info *thread)
101static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) 112static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
102{ 113{
103 struct thread_info *thread = v; 114 struct thread_info *thread = v;
115 u32 fpexc;
116#ifdef CONFIG_SMP
117 unsigned int cpu;
118#endif
104 119
105 if (likely(cmd == THREAD_NOTIFY_SWITCH)) { 120 switch (cmd) {
106 u32 fpexc = fmrx(FPEXC); 121 case THREAD_NOTIFY_SWITCH:
122 fpexc = fmrx(FPEXC);
107 123
108#ifdef CONFIG_SMP 124#ifdef CONFIG_SMP
109 unsigned int cpu = thread->cpu; 125 cpu = thread->cpu;
110 126
111 /* 127 /*
112 * On SMP, if VFP is enabled, save the old state in 128 * On SMP, if VFP is enabled, save the old state in
@@ -131,13 +147,20 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
131 * old state. 147 * old state.
132 */ 148 */
133 fmxr(FPEXC, fpexc & ~FPEXC_EN); 149 fmxr(FPEXC, fpexc & ~FPEXC_EN);
134 return NOTIFY_DONE; 150 break;
135 }
136 151
137 if (cmd == THREAD_NOTIFY_FLUSH) 152 case THREAD_NOTIFY_FLUSH:
138 vfp_thread_flush(thread); 153 vfp_thread_flush(thread);
139 else 154 break;
155
156 case THREAD_NOTIFY_EXIT:
140 vfp_thread_exit(thread); 157 vfp_thread_exit(thread);
158 break;
159
160 case THREAD_NOTIFY_COPY:
161 vfp_thread_copy(thread);
162 break;
163 }
141 164
142 return NOTIFY_DONE; 165 return NOTIFY_DONE;
143} 166}
@@ -150,7 +173,7 @@ static struct notifier_block vfp_notifier_block = {
150 * Raise a SIGFPE for the current process. 173 * Raise a SIGFPE for the current process.
151 * sicode describes the signal being raised. 174 * sicode describes the signal being raised.
152 */ 175 */
153void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs) 176static void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
154{ 177{
155 siginfo_t info; 178 siginfo_t info;
156 179
@@ -375,9 +398,9 @@ static void vfp_enable(void *unused)
375} 398}
376 399
377#ifdef CONFIG_PM 400#ifdef CONFIG_PM
378#include <linux/sysdev.h> 401#include <linux/syscore_ops.h>
379 402
380static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state) 403static int vfp_pm_suspend(void)
381{ 404{
382 struct thread_info *ti = current_thread_info(); 405 struct thread_info *ti = current_thread_info();
383 u32 fpexc = fmrx(FPEXC); 406 u32 fpexc = fmrx(FPEXC);
@@ -397,34 +420,25 @@ static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
397 return 0; 420 return 0;
398} 421}
399 422
400static int vfp_pm_resume(struct sys_device *dev) 423static void vfp_pm_resume(void)
401{ 424{
402 /* ensure we have access to the vfp */ 425 /* ensure we have access to the vfp */
403 vfp_enable(NULL); 426 vfp_enable(NULL);
404 427
405 /* and disable it to ensure the next usage restores the state */ 428 /* and disable it to ensure the next usage restores the state */
406 fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); 429 fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
407
408 return 0;
409} 430}
410 431
411static struct sysdev_class vfp_pm_sysclass = { 432static struct syscore_ops vfp_pm_syscore_ops = {
412 .name = "vfp",
413 .suspend = vfp_pm_suspend, 433 .suspend = vfp_pm_suspend,
414 .resume = vfp_pm_resume, 434 .resume = vfp_pm_resume,
415}; 435};
416 436
417static struct sys_device vfp_pm_sysdev = {
418 .cls = &vfp_pm_sysclass,
419};
420
421static void vfp_pm_init(void) 437static void vfp_pm_init(void)
422{ 438{
423 sysdev_class_register(&vfp_pm_sysclass); 439 register_syscore_ops(&vfp_pm_syscore_ops);
424 sysdev_register(&vfp_pm_sysdev);
425} 440}
426 441
427
428#else 442#else
429static inline void vfp_pm_init(void) { } 443static inline void vfp_pm_init(void) { }
430#endif /* CONFIG_PM */ 444#endif /* CONFIG_PM */
@@ -484,7 +498,27 @@ void vfp_flush_hwstate(struct thread_info *thread)
484 put_cpu(); 498 put_cpu();
485} 499}
486 500
487#include <linux/smp.h> 501/*
502 * VFP hardware can lose all context when a CPU goes offline.
503 * As we will be running in SMP mode with CPU hotplug, we will save the
504 * hardware state at every thread switch. We clear our held state when
505 * a CPU has been killed, indicating that the VFP hardware doesn't contain
506 * a threads VFP state. When a CPU starts up, we re-enable access to the
507 * VFP hardware.
508 *
509 * Both CPU_DYING and CPU_STARTING are called on the CPU which
510 * is being offlined/onlined.
511 */
512static int vfp_hotplug(struct notifier_block *b, unsigned long action,
513 void *hcpu)
514{
515 if (action == CPU_DYING || action == CPU_DYING_FROZEN) {
516 unsigned int cpu = (long)hcpu;
517 last_VFP_context[cpu] = NULL;
518 } else if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
519 vfp_enable(NULL);
520 return NOTIFY_OK;
521}
488 522
489/* 523/*
490 * VFP support code initialisation. 524 * VFP support code initialisation.
@@ -514,6 +548,8 @@ static int __init vfp_init(void)
514 else if (vfpsid & FPSID_NODOUBLE) { 548 else if (vfpsid & FPSID_NODOUBLE) {
515 printk("no double precision support\n"); 549 printk("no double precision support\n");
516 } else { 550 } else {
551 hotcpu_notifier(vfp_hotplug, 0);
552
517 smp_call_function(vfp_enable, NULL, 1); 553 smp_call_function(vfp_enable, NULL, 1);
518 554
519 VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */ 555 VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT; /* Extract the architecture version */