summaryrefslogtreecommitdiffstats
path: root/sys/pc98
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2001-05-21 12:20:22 +0000
committernyan <nyan@FreeBSD.org>2001-05-21 12:20:22 +0000
commit4303a8446df0bfbf44e109c692db0614bc63e3d0 (patch)
tree5c07ed287a9f4a08a1ae2142967fb689220df242 /sys/pc98
parentbd9386c173960ada6d5f1210373e6ab42ae10e36 (diff)
downloadFreeBSD-src-4303a8446df0bfbf44e109c692db0614bc63e3d0.zip
FreeBSD-src-4303a8446df0bfbf44e109c692db0614bc63e3d0.tar.gz
Merged from sys/i386/isa/npx.c revisions 1.99 and 1.100.
Diffstat (limited to 'sys/pc98')
-rw-r--r--sys/pc98/pc98/npx.c103
1 files changed, 29 insertions, 74 deletions
diff --git a/sys/pc98/pc98/npx.c b/sys/pc98/pc98/npx.c
index ecb8137..9b070a4 100644
--- a/sys/pc98/pc98/npx.c
+++ b/sys/pc98/pc98/npx.c
@@ -56,6 +56,7 @@
#include <sys/syslog.h>
#endif
#include <sys/signalvar.h>
+#include <sys/user.h>
#ifndef SMP
#include <machine/asmacros.h>
@@ -98,7 +99,6 @@
#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr)))
#define fnclex() __asm("fnclex")
#define fninit() __asm("fninit")
-#define fnop() __asm("fnop")
#define fnsave(addr) __asm __volatile("fnsave %0" : "=m" (*(addr)))
#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr)))
#define fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr)))
@@ -113,7 +113,6 @@
void fldcw __P((caddr_t addr));
void fnclex __P((void));
void fninit __P((void));
-void fnop __P((void));
void fnsave __P((caddr_t addr));
void fnstcw __P((caddr_t addr));
void fnstsw __P((caddr_t addr));
@@ -143,9 +142,6 @@ SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
"Floatingpoint instructions executed in hardware");
#ifndef SMP
-static u_int npx0_imask = 0;
-static struct gate_descriptor npx_idt_probeintr;
-static int npx_intrno;
static volatile u_int npx_intrs_while_probing;
static volatile u_int npx_traps_while_probing;
#endif
@@ -201,7 +197,6 @@ __asm(" \n\
");
#endif /* SMP */
-
/*
* Identify routine. Create a connection point on our parent for probing.
*/
@@ -239,6 +234,7 @@ npx_probe(dev)
#else /* SMP */
+ int npx_intrno;
int result;
critical_t savecrit;
u_char save_icu1_mask;
@@ -278,7 +274,6 @@ npx_probe(dev)
#endif
setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
- npx_idt_probeintr = idt[npx_intrno];
/*
* XXX This looks highly bogus, but it appears that npc_probe1
@@ -418,10 +413,6 @@ npx_probe1(dev)
* Bad, we are stuck with IRQ13.
*/
npx_irq13 = 1;
- /*
- * npxattach would be too late to set npx0_imask
- */
- npx0_imask |= (1 << npx_irq);
/*
* We allocate these resources permanently,
@@ -534,6 +525,7 @@ npxinit(control)
u_short control;
{
struct save87 dummy;
+ critical_t savecrit;
if (!npx_exists)
return;
@@ -542,12 +534,14 @@ npxinit(control)
* fnsave to throw away any junk in the fpu. npxsave() initializes
* the fpu and sets npxproc = NULL as important side effects.
*/
+ savecrit = critical_enter();
npxsave(&dummy);
stop_emulating();
fldcw(&control);
if (PCPU_GET(curpcb) != NULL)
fnsave(&PCPU_GET(curpcb)->pcb_savefpu);
start_emulating();
+ critical_exit(savecrit);
}
/*
@@ -557,9 +551,12 @@ void
npxexit(p)
struct proc *p;
{
+ critical_t savecrit;
+ savecrit = critical_enter();
if (p == PCPU_GET(npxproc))
npxsave(&PCPU_GET(curpcb)->pcb_savefpu);
+ critical_exit(savecrit);
#ifdef NPX_DEBUG
if (npx_exists) {
u_int masked_exceptions;
@@ -898,79 +895,37 @@ npxdna()
}
/*
- * Wrapper for fnsave instruction to handle h/w bugs. If there is an error
- * pending, then fnsave generates a bogus IRQ13 on some systems. Force
- * any IRQ13 to be handled immediately, and then ignore it. This routine is
- * often called at splhigh so it must not use many system services. In
- * particular, it's much easier to install a special handler than to
- * guarantee that it's safe to use npxintr() and its supporting code.
+ * Wrapper for fnsave instruction, partly to handle hardware bugs. When npx
+ * exceptions are reported via IRQ13, spurious IRQ13's may be triggered by
+ * no-wait npx instructions. See the Intel application note AP-578 for
+ * details. This doesn't cause any additional complications here. IRQ13's
+ * are inherently asynchronous unless the CPU is frozen to deliver them --
+ * one that started in userland may be delivered many instructions later,
+ * after the process has entered the kernel. It may even be delivered after
+ * the fnsave here completes. A spurious IRQ13 for the fnsave is handled in
+ * the same way as a very-late-arriving non-spurious IRQ13 from user mode:
+ * it is normally ignored at first because we set npxproc to NULL; it is
+ * normally retriggered in npxdna() after return to user mode.
+ *
+ * npxsave() must be called with interrupts disabled, so that it clears
+ * npxproc atomically with saving the state. We require callers to do the
+ * disabling, since most callers need to disable interrupts anyway to call
+ * npxsave() atomically with checking npxproc.
+ *
+ * A previous version of npxsave() went to great lengths to excecute fnsave
+ * with interrupts enabled in case executing it froze the CPU. This case
+ * can't happen, at least for Intel CPU/NPX's. Spurious IRQ13's don't imply
+ * spurious freezes.
*/
void
npxsave(addr)
struct save87 *addr;
{
-#ifdef SMP
stop_emulating();
fnsave(addr);
- /* fnop(); */
start_emulating();
PCPU_SET(npxproc, NULL);
-
-#else /* SMP */
-
- critical_t savecrit;
- u_char icu1_mask;
- u_char icu2_mask;
- u_char old_icu1_mask;
- u_char old_icu2_mask;
- struct gate_descriptor save_idt_npxintr;
-
- savecrit = critical_enter();
-#ifdef PC98
- old_icu1_mask = inb(IO_ICU1 + 2);
- old_icu2_mask = inb(IO_ICU2 + 2);
-#else
- old_icu1_mask = inb(IO_ICU1 + 1);
- old_icu2_mask = inb(IO_ICU2 + 1);
-#endif
- save_idt_npxintr = idt[npx_intrno];
-#ifdef PC98
- outb(IO_ICU1 + 2, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask));
- outb(IO_ICU2 + 2, old_icu2_mask & ~(npx0_imask >> 8));
-#else
- outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask));
- outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0_imask >> 8));
-#endif
- idt[npx_intrno] = npx_idt_probeintr;
- critical_exit(savecrit);
- stop_emulating();
- fnsave(addr);
- fnop();
- start_emulating();
- PCPU_SET(npxproc, NULL);
- savecrit = critical_enter();
-#ifdef PC98
- icu1_mask = inb(IO_ICU1 + 2); /* masks may have changed */
- icu2_mask = inb(IO_ICU2 + 2);
- outb(IO_ICU1 + 2,
- (icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask));
- outb(IO_ICU2 + 2,
- (icu2_mask & ~(npx0_imask >> 8))
- | (old_icu2_mask & (npx0_imask >> 8)));
-#else
- icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */
- icu2_mask = inb(IO_ICU2 + 1);
- outb(IO_ICU1 + 1,
- (icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask));
- outb(IO_ICU2 + 1,
- (icu2_mask & ~(npx0_imask >> 8))
- | (old_icu2_mask & (npx0_imask >> 8)));
-#endif
- idt[npx_intrno] = save_idt_npxintr;
- critical_exit(savecrit); /* back to previous state */
-
-#endif /* SMP */
}
#ifdef I586_CPU
OpenPOWER on IntegriCloud