diff options
author | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2013-07-19 12:48:08 -0400 |
---|---|---|
committer | Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | 2013-12-16 12:17:32 -0500 |
commit | fb1ab1ab3889fc23ed90e452502662311ebdf229 (patch) | |
tree | e75540da487021a89a933c0451635529d98c2915 | |
parent | 95322526ef62b84adb469c27535ab0252a369a85 (diff) |
arm64: kernel: implement fpsimd CPU PM notifier
When a CPU enters a low power state, its FP register content is lost.
This patch adds a notifier to save the FP context on CPU shutdown
and restore it on CPU resume. The context is saved and restored only
if the suspending thread is not a kernel thread, mirroring the current
context switch behaviour.
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
-rw-r--r-- | arch/arm64/kernel/fpsimd.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index bb785d23dbde..4aef42a04bdc 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/cpu_pm.h> | ||
20 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
21 | #include <linux/init.h> | 22 | #include <linux/init.h> |
22 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
@@ -113,6 +114,39 @@ EXPORT_SYMBOL(kernel_neon_end); | |||
113 | 114 | ||
114 | #endif /* CONFIG_KERNEL_MODE_NEON */ | 115 | #endif /* CONFIG_KERNEL_MODE_NEON */ |
115 | 116 | ||
117 | #ifdef CONFIG_CPU_PM | ||
118 | static int fpsimd_cpu_pm_notifier(struct notifier_block *self, | ||
119 | unsigned long cmd, void *v) | ||
120 | { | ||
121 | switch (cmd) { | ||
122 | case CPU_PM_ENTER: | ||
123 | if (current->mm) | ||
124 | fpsimd_save_state(¤t->thread.fpsimd_state); | ||
125 | break; | ||
126 | case CPU_PM_EXIT: | ||
127 | if (current->mm) | ||
128 | fpsimd_load_state(¤t->thread.fpsimd_state); | ||
129 | break; | ||
130 | case CPU_PM_ENTER_FAILED: | ||
131 | default: | ||
132 | return NOTIFY_DONE; | ||
133 | } | ||
134 | return NOTIFY_OK; | ||
135 | } | ||
136 | |||
137 | static struct notifier_block fpsimd_cpu_pm_notifier_block = { | ||
138 | .notifier_call = fpsimd_cpu_pm_notifier, | ||
139 | }; | ||
140 | |||
141 | static void fpsimd_pm_init(void) | ||
142 | { | ||
143 | cpu_pm_register_notifier(&fpsimd_cpu_pm_notifier_block); | ||
144 | } | ||
145 | |||
146 | #else | ||
147 | static inline void fpsimd_pm_init(void) { } | ||
148 | #endif /* CONFIG_CPU_PM */ | ||
149 | |||
116 | /* | 150 | /* |
117 | * FP/SIMD support code initialisation. | 151 | * FP/SIMD support code initialisation. |
118 | */ | 152 | */ |
@@ -131,6 +165,8 @@ static int __init fpsimd_init(void) | |||
131 | else | 165 | else |
132 | elf_hwcap |= HWCAP_ASIMD; | 166 | elf_hwcap |= HWCAP_ASIMD; |
133 | 167 | ||
168 | fpsimd_pm_init(); | ||
169 | |||
134 | return 0; | 170 | return 0; |
135 | } | 171 | } |
136 | late_initcall(fpsimd_init); | 172 | late_initcall(fpsimd_init); |