aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2013-07-19 12:48:08 -0400
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2013-12-16 12:17:32 -0500
commitfb1ab1ab3889fc23ed90e452502662311ebdf229 (patch)
treee75540da487021a89a933c0451635529d98c2915
parent95322526ef62b84adb469c27535ab0252a369a85 (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.c36
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
118static 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(&current->thread.fpsimd_state);
125 break;
126 case CPU_PM_EXIT:
127 if (current->mm)
128 fpsimd_load_state(&current->thread.fpsimd_state);
129 break;
130 case CPU_PM_ENTER_FAILED:
131 default:
132 return NOTIFY_DONE;
133 }
134 return NOTIFY_OK;
135}
136
137static struct notifier_block fpsimd_cpu_pm_notifier_block = {
138 .notifier_call = fpsimd_cpu_pm_notifier,
139};
140
141static void fpsimd_pm_init(void)
142{
143 cpu_pm_register_notifier(&fpsimd_cpu_pm_notifier_block);
144}
145
146#else
147static 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}
136late_initcall(fpsimd_init); 172late_initcall(fpsimd_init);