Initial Contribution

msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142

Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index f25e7ec..3554500 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -397,30 +397,45 @@
 	set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
 }
 
-#ifdef CONFIG_PM
-#include <linux/syscore_ops.h>
-
-static int vfp_pm_suspend(void)
+int vfp_flush_context(void)
 {
-	struct thread_info *ti = current_thread_info();
-	u32 fpexc = fmrx(FPEXC);
+	unsigned long flags;
+	struct thread_info *ti;
+	u32 fpexc;
+	u32 cpu;
+	int saved = 0;
 
-	/* if vfp is on, then save state for resumption */
-	if (fpexc & FPEXC_EN) {
-		printk(KERN_DEBUG "%s: saving vfp state\n", __func__);
-		vfp_save_state(&ti->vfpstate, fpexc);
+	local_irq_save(flags);
+
+	ti = current_thread_info();
+	fpexc = fmrx(FPEXC);
+	cpu = ti->cpu;
+
+#ifdef CONFIG_SMP
+	/* On SMP, if VFP is enabled, save the old state */
+	if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) {
+		last_VFP_context[cpu]->hard.cpu = cpu;
+#else
+	/* If there is a VFP context we must save it. */
+	if (last_VFP_context[cpu]) {
+		/* Enable VFP so we can save the old state. */
+		fmxr(FPEXC, fpexc | FPEXC_EN);
+		isb();
+#endif
+		vfp_save_state(last_VFP_context[cpu], fpexc);
 
 		/* disable, just in case */
 		fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
+		saved = 1;
 	}
+	last_VFP_context[cpu] = NULL;
 
-	/* clear any information we had about last context state */
-	memset(last_VFP_context, 0, sizeof(last_VFP_context));
+	local_irq_restore(flags);
 
-	return 0;
+	return saved;
 }
 
-static void vfp_pm_resume(void)
+void vfp_reinit(void)
 {
 	/* ensure we have access to the vfp */
 	vfp_enable(NULL);
@@ -429,6 +444,21 @@
 	fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
 }
 
+#ifdef CONFIG_PM
+#include <linux/syscore_ops.h>
+
+static int vfp_pm_suspend(void)
+{
+	vfp_flush_context();
+
+	return 0;
+}
+
+static void vfp_pm_resume(void)
+{
+	vfp_reinit();
+}
+
 static struct syscore_ops vfp_pm_syscore_ops = {
 	.suspend	= vfp_pm_suspend,
 	.resume		= vfp_pm_resume,