]> xenbits.xensource.com Git - people/aperard/linux-chromebook.git/commitdiff
BACKPORT: x86, fpu: avoid FPU lazy restore after suspend
authorVincent Palatin <vpalatin@chromium.org>
Fri, 30 Nov 2012 17:33:44 +0000 (09:33 -0800)
committerGerrit <chrome-bot@google.com>
Sat, 1 Dec 2012 01:26:29 +0000 (17:26 -0800)
When a cpu enters S3 state, the FPU state is lost.
After resuming for S3, if we try to lazy restore the FPU for a process running
on the same CPU, this will result in a corrupted FPU context.

Ensure that "fpu_owner_task" is properly invalided when (re-)initializing a CPU,
so nobody will try to lazy restore a state which doesn't exist in the hardware.

Cc: Duncan Laurie <dlaurie@chromium.org>
Cc: Olof Johansson <olofj@chromium.org>
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BUG=chrome-os-partner:16295
TEST=On Link, run thousands of suspend/resume cycles with 4 processes doing FPU
operations running as described in the bug.
Without the patch, a process is killed after a few hundreds cycles by a SIGFPE.

Change-Id: I33ee884dea6cad048cbe1aa60c64cbb5141d3f66
Reviewed-on: https://gerrit.chromium.org/gerrit/39006
Commit-Ready: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Olof Johansson <olofj@chromium.org>
arch/x86/include/asm/fpu-internal.h
arch/x86/kernel/smpboot.c

index 4fa88154e4dec6d93eaeadbeb1d991a02e57f835..92e05b6c84f801895b85ff718684a4e0ac0aa6c6 100644 (file)
@@ -334,14 +334,17 @@ static inline void __thread_fpu_begin(struct task_struct *tsk)
 typedef struct { int preload; } fpu_switch_t;
 
 /*
- * FIXME! We could do a totally lazy restore, but we need to
- * add a per-cpu "this was the task that last touched the FPU
- * on this CPU" variable, and the task needs to have a "I last
- * touched the FPU on this CPU" and check them.
+ * Must be run with preemption disabled: this clears the fpu_owner_task,
+ * on this CPU.
  *
- * We don't do that yet, so "fpu_lazy_restore()" always returns
- * false, but some day..
+ * This will disable any lazy FPU state restore of the current FPU state,
+ * but if the current thread owns the FPU, it will still be saved by.
  */
+static inline void __cpu_disable_lazy_restore(unsigned int cpu)
+{
+       per_cpu(fpu_owner_task, cpu) = NULL;
+}
+
 static inline int fpu_lazy_restore(struct task_struct *new, unsigned int cpu)
 {
        return new == percpu_read_stable(fpu_owner_task) &&
index 6e1e406038c23d963ee12fcab76abca544cc1d86..849cdcf2e76ab11a0fcba331b68d3da2d0641839 100644 (file)
@@ -66,6 +66,8 @@
 #include <asm/mwait.h>
 #include <asm/apic.h>
 #include <asm/io_apic.h>
+#include <asm/i387.h>
+#include <asm/fpu-internal.h>
 #include <asm/setup.h>
 #include <asm/uv/uv.h>
 #include <linux/mc146818rtc.h>
@@ -851,6 +853,9 @@ int __cpuinit native_cpu_up(unsigned int cpu)
 
        per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
 
+       /* the FPU context is blank, nobody can own it */
+       __cpu_disable_lazy_restore(cpu);
+
        err = do_boot_cpu(apicid, cpu);
        if (err) {
                pr_debug("do_boot_cpu failed %d\n", err);