Module Name:    src
Committed By:   skrll
Date:           Sat Jan 25 17:30:56 UTC 2014

Modified Files:
        src/sys/arch/arm/vfp: vfp_init.c

Log Message:
Improve PCU/VFP handling to the point that the atf tests don't trigger
KASSERTs on the Raspberry PI and its arm1176jzf-s.

XXX Need to emulate bounce instructions to get correct exception codes,
XXX etc.


To generate a diff of this commit:
cvs rdiff -u -r1.32 -r1.33 src/sys/arch/arm/vfp/vfp_init.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/arm/vfp/vfp_init.c
diff -u src/sys/arch/arm/vfp/vfp_init.c:1.32 src/sys/arch/arm/vfp/vfp_init.c:1.33
--- src/sys/arch/arm/vfp/vfp_init.c:1.32	Fri Jan 24 08:26:39 2014
+++ src/sys/arch/arm/vfp/vfp_init.c	Sat Jan 25 17:30:56 2014
@@ -1,4 +1,4 @@
-/*      $NetBSD: vfp_init.c,v 1.32 2014/01/24 08:26:39 skrll Exp $ */
+/*      $NetBSD: vfp_init.c,v 1.33 2014/01/25 17:30:56 skrll Exp $ */
 
 /*
  * Copyright (c) 2008 ARM Ltd
@@ -407,14 +407,18 @@ vfp_handler(u_int address, u_int insn, t
 
 		vfpevent_fpe.ev_count++;
 
-		pcu_save(&arm_vfp_ops);
-
 		/*
 		 * Need the clear the exception condition so any signal
-		 * can run.
+		 * and future use can proceed.
 		 */
 		armreg_fpexc_write(fpexc & ~(VFP_FPEXC_EX|VFP_FPEXC_FSUM));
 
+		pcu_save(&arm_vfp_ops);
+
+		/*
+		 * XXX Need to emulate bounce instructions here to get correct
+		 * XXX exception codes, etc.
+		 */
 		KSI_INIT_TRAP(&ksi);
 		ksi.ksi_signo = SIGFPE;
 		if (fpexc & VFP_FPEXC_IXF)
@@ -499,6 +503,7 @@ vfp_state_load(lwp_t *l, u_int flags)
 	 * a trap to use it again" event.
 	 */
 	if (__predict_false((flags & PCU_LOADED) == 0)) {
+		KASSERT(flags & PCU_RELOAD);
 		vfpevent_use.ev_count++;
 		pcb->pcb_vfp.vfp_fpscr =
 		    (VFP_FPSCR_DN | VFP_FPSCR_FZ | VFP_FPSCR_RN); /* Runfast */
@@ -506,21 +511,24 @@ vfp_state_load(lwp_t *l, u_int flags)
 		vfpevent_reuse.ev_count++;
 	}
 
-	if (fregs->vfp_fpexc & VFP_FPEXC_EN) {
+	uint32_t fpexc = armreg_fpexc_read();
+	if (flags & PCU_RELOAD) {
+		bool enabled = fregs->vfp_fpexc & VFP_FPEXC_EN;
+
 		/*
-		 * If we think the VFP is enabled, it must have be disabled by
-		 * vfp_state_release for another LWP so we can just restore
-		 * FPEXC and return since our VFP state is still loaded.
+		 * Load and Enable the VFP (so that we can write the
+		 * registers).
 		 */
+		fregs->vfp_fpexc |= VFP_FPEXC_EN;
 		armreg_fpexc_write(fregs->vfp_fpexc);
-		return;
-	}
-
-	/* Load and Enable the VFP (so that we can write the registers).  */
-	if (flags & PCU_RELOAD) {
-		uint32_t fpexc = armreg_fpexc_read();
-		KDASSERT((fpexc & VFP_FPEXC_EX) == 0);
-		armreg_fpexc_write(fpexc | VFP_FPEXC_EN);
+		if (enabled) {
+			/*
+			 * If we think the VFP is enabled, it must have be
+			 * disabled by vfp_state_release for another LWP so
+			 * we can now just return.
+			 */
+			return;
+		}
 
 		load_vfpregs(fregs);
 		armreg_fpscr_write(fregs->vfp_fpscr);
@@ -531,11 +539,13 @@ vfp_state_load(lwp_t *l, u_int flags)
 			if (fregs->vfp_fpexc & VFP_FPEXC_FP2V)
 				armreg_fpinst_write(fregs->vfp_fpinst);
 		}
+	} else {
+		/*
+		 * If the VFP is already enabled we must be bouncing an
+		 * instruction.
+		 */
+		armreg_fpexc_write(fpexc | VFP_FPEXC_EN);
 	}
-
-	/* Finally, restore the FPEXC but don't enable the VFP. */
-	fregs->vfp_fpexc |= VFP_FPEXC_EN;
-	armreg_fpexc_write(fregs->vfp_fpexc);
 }
 
 void
@@ -543,6 +553,12 @@ vfp_state_save(lwp_t *l, u_int flags)
 {
 	struct pcb * const pcb = lwp_getpcb(l);
 	uint32_t fpexc = armreg_fpexc_read();
+
+	/*
+	 * Enable the VFP (so we can read the registers).
+	 * Make sure the exception bit is cleared so that we can
+	 * safely dump the registers.
+	 */
 	armreg_fpexc_write((fpexc | VFP_FPEXC_EN) & ~VFP_FPEXC_EX);
 
 	if (flags & PCU_KERNEL) {
@@ -556,11 +572,6 @@ vfp_state_save(lwp_t *l, u_int flags)
 
 	struct vfpreg * const fregs = &pcb->pcb_vfp;
 
-	/*
-	 * Enable the VFP (so we can read the registers).  
-	 * Make sure the exception bit is cleared so that we can
-	 * safely dump the registers.
-	 */
 	fregs->vfp_fpexc = fpexc;
 	if (fpexc & VFP_FPEXC_EX) {
 		/* Need to save the exception handling state */
@@ -572,7 +583,7 @@ vfp_state_save(lwp_t *l, u_int flags)
 	save_vfpregs(fregs);
 
 	/* Disable the VFP.  */
-	armreg_fpexc_write(fpexc);
+	armreg_fpexc_write(fpexc & ~VFP_FPEXC_EN);
 }
 
 void

Reply via email to