summaryrefslogtreecommitdiffstats
path: root/sys/ia64
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2003-11-12 01:26:02 +0000
committermarcel <marcel@FreeBSD.org>2003-11-12 01:26:02 +0000
commit19c69bbd49c4d95a3cf228c609e4ee3257649d3a (patch)
tree7b376a522336a8c9ffd97c3c91a85f1333fbc1f2 /sys/ia64
parentdfaa7af61be5f69136519a90e14b1615b99b931d (diff)
downloadFreeBSD-src-19c69bbd49c4d95a3cf228c609e4ee3257649d3a.zip
FreeBSD-src-19c69bbd49c4d95a3cf228c609e4ee3257649d3a.tar.gz
Further work-out the handling of the high FP registers. The most
important change is in cpu_switch() where we disable the high FP registers for the thread that we switch-out if the CPU currently has its high FP registers. This avoids that the high FP registers remain enabled for the thread even when the CPU has unloaded them or the thread migrated to another processor. Likewise, when we switch-in a thread of that has its high FP registers on the CPU, we enable them. This avoids an otherwise harmless, but unnecessary trap to have them enabled. The code that handles the disabled high FP trap (in trap()) has been turned into a critical section for the most part to avoid being preempted. If there's a race, we bail out and have the processor trap again if necessary. Avoid using the generic ia64_highfp_save() function when the context is predictable. The function adds unnecessary overhead. Don't use ia64_highfp_load() for the same reason. The function is now unused and can be removed. These changes make the lazy context switching of the high FP registers in an UP kernel functional.
Diffstat (limited to 'sys/ia64')
-rw-r--r--sys/ia64/ia64/interrupt.c8
-rw-r--r--sys/ia64/ia64/machdep.c4
-rw-r--r--sys/ia64/ia64/trap.c103
3 files changed, 48 insertions, 67 deletions
diff --git a/sys/ia64/ia64/interrupt.c b/sys/ia64/ia64/interrupt.c
index 0fb9053..5c71c01 100644
--- a/sys/ia64/ia64/interrupt.c
+++ b/sys/ia64/ia64/interrupt.c
@@ -200,8 +200,12 @@ interrupt(u_int64_t vector, struct trapframe *framep)
asts[PCPU_GET(cpuid)]++;
CTR1(KTR_SMP, "IPI_AST, cpuid=%d", PCPU_GET(cpuid));
} else if (vector == ipi_vector[IPI_HIGH_FP]) {
- if (PCPU_GET(fpcurthread) != NULL)
- ia64_highfp_save(PCPU_GET(fpcurthread));
+ struct thread *thr = PCPU_GET(fpcurthread);
+ if (thr != NULL) {
+ save_high_fp(&thr->td_pcb->pcb_high_fp);
+ thr->td_pcb->pcb_fpcpu = NULL;
+ PCPU_SET(fpcurthread, NULL);
+ }
} else if (vector == ipi_vector[IPI_RENDEZVOUS]) {
rdvs[PCPU_GET(cpuid)]++;
CTR1(KTR_SMP, "IPI_RENDEZVOUS, cpuid=%d", PCPU_GET(cpuid));
diff --git a/sys/ia64/ia64/machdep.c b/sys/ia64/ia64/machdep.c
index e17a02c..34cdff1 100644
--- a/sys/ia64/ia64/machdep.c
+++ b/sys/ia64/ia64/machdep.c
@@ -311,6 +311,8 @@ cpu_switch(struct thread *old, struct thread *new)
#if IA32
ia32_savectx(oldpcb);
#endif
+ if (PCPU_GET(fpcurthread) == old)
+ old->td_frame->tf_special.psr |= IA64_PSR_DFH;
if (!savectx(oldpcb)) {
newpcb = new->td_pcb;
oldpcb->pcb_current_pmap =
@@ -319,6 +321,8 @@ cpu_switch(struct thread *old, struct thread *new)
#if IA32
ia32_restorectx(newpcb);
#endif
+ if (PCPU_GET(fpcurthread) == new)
+ new->td_frame->tf_special.psr &= ~IA64_PSR_DFH;
restorectx(newpcb);
/* We should not get here. */
panic("cpu_switch: restorectx() returned");
diff --git a/sys/ia64/ia64/trap.c b/sys/ia64/ia64/trap.c
index 9124a89..96df125 100644
--- a/sys/ia64/ia64/trap.c
+++ b/sys/ia64/ia64/trap.c
@@ -570,81 +570,54 @@ trap(int vector, struct trapframe *framep)
if (!user)
trap_panic(vector, framep);
+ critical_enter();
+ thr = PCPU_GET(fpcurthread);
+ if (thr == td) {
+ /*
+ * Short-circuit handling the trap when this CPU
+ * already holds the high FP registers for this
+ * thread. We really shouldn't get the trap in the
+ * first place, but since it's only a performance
+ * issue and not a correctness issue, we emit a
+ * message for now, enable the high FP registers and
+ * return.
+ */
+ printf("XXX: bogusly disabled high FP regs\n");
+ framep->tf_special.psr &= ~IA64_PSR_DFH;
+ critical_exit();
+ goto out;
+ } else if (thr != NULL) {
+ pcb = thr->td_pcb;
+ save_high_fp(&pcb->pcb_high_fp);
+ pcb->pcb_fpcpu = NULL;
+ PCPU_SET(fpcurthread, NULL);
+ thr = NULL;
+ }
+
pcb = td->td_pcb;
pcpu = pcb->pcb_fpcpu;
-#if 0
- printf("XXX: td %p: highfp on cpu %p\n", td, pcpu);
-#endif
-
- /*
- * The pcpu variable holds the address of the per-CPU
- * structure of the CPU currently holding this threads
- * high FP registers (or NULL if no CPU holds these
- * registers). We have to interrupt that CPU and wait
- * for it to have saved the registers.
- */
- if (pcpu != NULL) {
- thr = pcpu->pc_fpcurthread;
- KASSERT(thr == td, ("High FP state out of sync"));
-
- if (pcpu == pcpup) {
- /*
- * Short-circuit handling the trap when this
- * CPU already holds the high FP registers for
- * this thread. We really shouldn't get the
- * trap in the first place, but since it's
- * only a performance issue and not a
- * correctness issue, we emit a message for
- * now, enable the high FP registers and
- * return.
- */
- printf("XXX: bogusly disabled high FP regs\n");
- framep->tf_special.psr &= ~IA64_PSR_DFH;
- goto out;
- }
#ifdef SMP
- /*
- * Interrupt the other CPU so that it saves the high
- * FP registers of this thread. Note that this can
- * only happen for the SMP case.
- */
+ if (pcpu != NULL) {
ipi_send(pcpu->pc_lid, IPI_HIGH_FP);
-#endif
-#ifdef DIAGNOSTICS
- } else {
- KASSERT(PCPU_GET(fpcurthread) != td,
- ("High FP state out of sync"));
-#endif
+ critical_exit();
+ while (pcb->pcb_fpcpu != pcpu)
+ DELAY(100);
+ critical_enter();
+ pcpu = pcb->pcb_fpcpu;
+ thr = PCPU_GET(fpcurthread);
}
-
- thr = PCPU_GET(fpcurthread);
-
-#if 0
- printf("XXX: cpu %p: highfp belongs to td %p\n", pcpup, thr);
#endif
- /*
- * The thr variable holds the thread that owns the high FP
- * registers currently on this CPU. Free this CPU so that
- * we can load the current threads high FP registers.
- */
- if (thr != NULL) {
- KASSERT(thr != td, ("High FP state out of sync"));
- pcb = thr->td_pcb;
- KASSERT(pcb->pcb_fpcpu == pcpup,
- ("High FP state out of sync"));
- ia64_highfp_save(thr);
+ if (thr == NULL && pcpu == NULL) {
+ restore_high_fp(&pcb->pcb_high_fp);
+ PCPU_SET(fpcurthread, td);
+ pcb->pcb_fpcpu = pcpup;
+ framep->tf_special.psr &= ~IA64_PSR_MFH;
+ framep->tf_special.psr &= ~IA64_PSR_DFH;
}
- /*
- * Wait for the other CPU to have saved out high FP
- * registers (if applicable).
- */
- while (pcpu && pcpu->pc_fpcurthread == td);
-
- ia64_highfp_load(td);
- framep->tf_special.psr &= ~IA64_PSR_DFH;
+ critical_exit();
goto out;
}
OpenPOWER on IntegriCloud