MFi386: sys/i386/isa/npx.c revisions from 1.114 to 1.116
This commit is contained in:
parent
8979160a62
commit
00da2ef3cc
@ -76,7 +76,6 @@
|
||||
|
||||
#ifndef SMP
|
||||
#include <i386/isa/icu.h>
|
||||
#include <i386/isa/intr_machdep.h>
|
||||
#ifdef PC98
|
||||
#include <pc98/pc98/pc98.h>
|
||||
#else
|
||||
@ -162,7 +161,6 @@ static void npx_identify __P((driver_t *driver, device_t parent));
|
||||
static void npx_intr __P((void *));
|
||||
#endif
|
||||
static int npx_probe __P((device_t dev));
|
||||
static int npx_probe1 __P((device_t dev));
|
||||
static void fpusave __P((union savefpu *));
|
||||
static void fpurstor __P((union savefpu *));
|
||||
#ifdef I586_CPU_XXX
|
||||
@ -184,42 +182,9 @@ static volatile u_int npx_traps_while_probing;
|
||||
static bool_t npx_ex16;
|
||||
static bool_t npx_exists;
|
||||
static bool_t npx_irq13;
|
||||
static int npx_irq; /* irq number */
|
||||
|
||||
#ifndef SMP
|
||||
/*
|
||||
* Special interrupt handlers. Someday intr0-intr15 will be used to count
|
||||
* interrupts. We'll still need a special exception 16 handler. The busy
|
||||
* latch stuff in probeintr() can be moved to npxprobe().
|
||||
*/
|
||||
inthand_t probeintr;
|
||||
__asm(" \n\
|
||||
.text \n\
|
||||
.p2align 2,0x90 \n\
|
||||
.type " __XSTRING(CNAME(probeintr)) ",@function \n\
|
||||
" __XSTRING(CNAME(probeintr)) ": \n\
|
||||
ss \n\
|
||||
incl " __XSTRING(CNAME(npx_intrs_while_probing)) " \n\
|
||||
pushl %eax \n\
|
||||
movb $0x20,%al # EOI (asm in strings loses cpp features) \n\
|
||||
#ifdef PC98
|
||||
outb %al,$0x08 # IO_ICU2 \n\
|
||||
outb %al,$0x00 # IO_ICU1 \n\
|
||||
#else
|
||||
outb %al,$0xa0 # IO_ICU2 \n\
|
||||
outb %al,$0x20 # IO_ICU1 \n\
|
||||
#endif
|
||||
movb $0,%al \n\
|
||||
#ifdef PC98
|
||||
outb %al,$0xf8 # clear BUSY# latch \n\
|
||||
#else
|
||||
outb %al,$0xf0 # clear BUSY# latch \n\
|
||||
#endif
|
||||
popl %eax \n\
|
||||
iret \n\
|
||||
");
|
||||
|
||||
inthand_t probetrap;
|
||||
alias_for_inthand_t probetrap;
|
||||
__asm(" \n\
|
||||
.text \n\
|
||||
.p2align 2,0x90 \n\
|
||||
@ -257,6 +222,10 @@ npx_intr(dummy)
|
||||
{
|
||||
struct thread *td;
|
||||
|
||||
#ifndef SMP
|
||||
npx_intrs_while_probing++;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The BUSY# latch must be cleared in all cases so that the next
|
||||
* unmasked npx exception causes an interrupt.
|
||||
@ -287,107 +256,49 @@ npx_intr(dummy)
|
||||
mtx_unlock_spin(&sched_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX these "local" variables of npx_probe() are non-local so that
|
||||
* npxprobe1() can abuse them.
|
||||
*/
|
||||
static int npx_intrno;
|
||||
static struct gate_descriptor save_idt_npxintr;
|
||||
#endif /* !SMP */
|
||||
|
||||
/*
|
||||
* Probe routine. Initialize cr0 to give correct behaviour for [f]wait
|
||||
* whether the device exists or not (XXX should be elsewhere). Set flags
|
||||
* to tell npxattach() what to do. Modify device struct if npx doesn't
|
||||
* need to use interrupts. Return 1 if device exists.
|
||||
* need to use interrupts. Return 0 if device exists.
|
||||
*/
|
||||
static int
|
||||
npx_probe(dev)
|
||||
device_t dev;
|
||||
{
|
||||
#ifdef SMP
|
||||
|
||||
if (resource_int_value("npx", 0, "irq", &npx_irq) != 0)
|
||||
#ifdef PC98
|
||||
npx_irq = 8;
|
||||
#else
|
||||
npx_irq = 13;
|
||||
#endif
|
||||
return npx_probe1(dev);
|
||||
|
||||
#else /* SMP */
|
||||
|
||||
int result;
|
||||
critical_t savecrit;
|
||||
u_char save_icu1_mask;
|
||||
u_char save_icu2_mask;
|
||||
struct gate_descriptor save_idt_npxtrap;
|
||||
/*
|
||||
* This routine is now just a wrapper for npxprobe1(), to install
|
||||
* special npx interrupt and trap handlers, to enable npx interrupts
|
||||
* and to disable other interrupts. Someday isa_configure() will
|
||||
* install suitable handlers and run with interrupts enabled so we
|
||||
* won't need to do so much here.
|
||||
*/
|
||||
if (resource_int_value("npx", 0, "irq", &npx_irq) != 0)
|
||||
#ifdef PC98
|
||||
npx_irq = 8;
|
||||
#else
|
||||
npx_irq = 13;
|
||||
#endif
|
||||
npx_intrno = NRSVIDT + npx_irq;
|
||||
savecrit = critical_enter();
|
||||
#ifdef PC98
|
||||
save_icu1_mask = inb(IO_ICU1 + 2);
|
||||
save_icu2_mask = inb(IO_ICU2 + 2);
|
||||
#else
|
||||
save_icu1_mask = inb(IO_ICU1 + 1);
|
||||
save_icu2_mask = inb(IO_ICU2 + 1);
|
||||
#endif
|
||||
save_idt_npxintr = idt[npx_intrno];
|
||||
save_idt_npxtrap = idt[16];
|
||||
#ifdef PC98
|
||||
outb(IO_ICU1 + 2, (u_int8_t) ~IRQ_SLAVE);
|
||||
outb(IO_ICU2 + 2, ~(1 << (npx_irq - 8)));
|
||||
#else
|
||||
outb(IO_ICU1 + 1, ~IRQ_SLAVE);
|
||||
outb(IO_ICU2 + 1, ~(1 << (npx_irq - 8)));
|
||||
#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));
|
||||
|
||||
/*
|
||||
* XXX This looks highly bogus, but it appears that npc_probe1
|
||||
* needs interrupts enabled. Does this make any difference
|
||||
* here?
|
||||
*/
|
||||
critical_exit(savecrit);
|
||||
result = npx_probe1(dev);
|
||||
savecrit = critical_enter();
|
||||
#ifdef PC98
|
||||
outb(IO_ICU1 + 2, save_icu1_mask);
|
||||
outb(IO_ICU2 + 2, save_icu2_mask);
|
||||
#else
|
||||
outb(IO_ICU1 + 1, save_icu1_mask);
|
||||
outb(IO_ICU2 + 1, save_icu2_mask);
|
||||
#endif
|
||||
idt[npx_intrno] = save_idt_npxintr;
|
||||
idt[16] = save_idt_npxtrap;
|
||||
critical_exit(savecrit);
|
||||
return (result);
|
||||
|
||||
#endif /* SMP */
|
||||
}
|
||||
|
||||
static int
|
||||
npx_probe1(dev)
|
||||
device_t dev;
|
||||
{
|
||||
#ifndef SMP
|
||||
struct gate_descriptor save_idt_npxtrap;
|
||||
struct resource *ioport_res, *irq_res;
|
||||
void *irq_cookie;
|
||||
int ioport_rid, irq_num, irq_rid;
|
||||
u_short control;
|
||||
u_short status;
|
||||
|
||||
save_idt_npxtrap = idt[16];
|
||||
setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
|
||||
ioport_rid = 0;
|
||||
ioport_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &ioport_rid,
|
||||
IO_NPX, IO_NPX, IO_NPXSIZE, RF_ACTIVE);
|
||||
if (ioport_res == NULL)
|
||||
panic("npx: can't get ports");
|
||||
#ifdef PC98
|
||||
if (resource_int_value("npx", 0, "irq", &irq_num) != 0)
|
||||
irq_num = 8;
|
||||
#else
|
||||
if (resource_int_value("npx", 0, "irq", &irq_num) != 0)
|
||||
irq_num = 13;
|
||||
#endif
|
||||
irq_rid = 0;
|
||||
irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &ioport_rid, irq_num,
|
||||
irq_num, 1, RF_ACTIVE);
|
||||
if (irq_res == NULL)
|
||||
panic("npx: can't get IRQ");
|
||||
if (bus_setup_intr(dev, irq_res, INTR_TYPE_MISC | INTR_FAST, npx_intr,
|
||||
NULL, &irq_cookie) != 0)
|
||||
panic("npx: can't create intr");
|
||||
#endif /* !SMP */
|
||||
|
||||
/*
|
||||
* Partially reset the coprocessor, if any. Some BIOS's don't reset
|
||||
@ -420,23 +331,23 @@ npx_probe1(dev)
|
||||
stop_emulating();
|
||||
/*
|
||||
* Finish resetting the coprocessor, if any. If there is an error
|
||||
* pending, then we may get a bogus IRQ13, but probeintr() will handle
|
||||
* pending, then we may get a bogus IRQ13, but npx_intr() will handle
|
||||
* it OK. Bogus halts have never been observed, but we enabled
|
||||
* IRQ13 and cleared the BUSY# latch early to handle them anyway.
|
||||
*/
|
||||
fninit();
|
||||
|
||||
device_set_desc(dev, "math processor");
|
||||
|
||||
#ifdef SMP
|
||||
|
||||
/*
|
||||
* Exception 16 MUST work for SMP.
|
||||
*/
|
||||
npx_irq13 = 0;
|
||||
npx_ex16 = hw_float = npx_exists = 1;
|
||||
device_set_desc(dev, "math processor");
|
||||
return (0);
|
||||
|
||||
#else /* !SMP */
|
||||
device_set_desc(dev, "math processor");
|
||||
|
||||
/*
|
||||
* Don't use fwait here because it might hang.
|
||||
@ -485,49 +396,14 @@ npx_probe1(dev)
|
||||
* Good, exception 16 works.
|
||||
*/
|
||||
npx_ex16 = 1;
|
||||
return (0);
|
||||
goto no_irq13;
|
||||
}
|
||||
if (npx_intrs_while_probing != 0) {
|
||||
int rid;
|
||||
struct resource *r;
|
||||
void *intr;
|
||||
/*
|
||||
* Bad, we are stuck with IRQ13.
|
||||
*/
|
||||
npx_irq13 = 1;
|
||||
|
||||
/*
|
||||
* We allocate these resources permanently,
|
||||
* so there is no need to keep track of them.
|
||||
*/
|
||||
rid = 0;
|
||||
r = bus_alloc_resource(dev, SYS_RES_IOPORT,
|
||||
&rid, IO_NPX, IO_NPX,
|
||||
IO_NPXSIZE, RF_ACTIVE);
|
||||
if (r == 0)
|
||||
panic("npx: can't get ports");
|
||||
rid = 0;
|
||||
r = bus_alloc_resource(dev, SYS_RES_IRQ,
|
||||
&rid, npx_irq, npx_irq,
|
||||
1, RF_ACTIVE);
|
||||
if (r == 0)
|
||||
panic("npx: can't get IRQ");
|
||||
BUS_SETUP_INTR(device_get_parent(dev),
|
||||
dev, r,
|
||||
INTR_TYPE_MISC | INTR_FAST,
|
||||
npx_intr, 0, &intr);
|
||||
if (intr == 0)
|
||||
panic("npx: can't create intr");
|
||||
|
||||
/*
|
||||
* XXX BUS_SETUP_INTR() has changed
|
||||
* idt[npx_intrno] to point to Xfastintr0
|
||||
* instead of Xfastintr0. Adjust
|
||||
* save_idt_npxintr so that npxprobe()
|
||||
* doesn't undo this.
|
||||
*/
|
||||
save_idt_npxintr = idt[npx_intrno];
|
||||
|
||||
idt[16] = save_idt_npxtrap;
|
||||
return (0);
|
||||
}
|
||||
/*
|
||||
@ -540,7 +416,21 @@ npx_probe1(dev)
|
||||
* emulator and say that it has been installed. XXX handle devices
|
||||
* that aren't really devices better.
|
||||
*/
|
||||
/* FALLTHROUGH */
|
||||
no_irq13:
|
||||
idt[16] = save_idt_npxtrap;
|
||||
bus_teardown_intr(dev, irq_res, irq_cookie);
|
||||
|
||||
/*
|
||||
* XXX hack around brokenness of bus_teardown_intr(). If we left the
|
||||
* irq active then we would get it instead of exception 16.
|
||||
*/
|
||||
INTRDIS(1 << irq_num);
|
||||
|
||||
bus_release_resource(dev, SYS_RES_IRQ, irq_rid, irq_res);
|
||||
bus_release_resource(dev, SYS_RES_IOPORT, ioport_rid, ioport_res);
|
||||
return (0);
|
||||
|
||||
#endif /* SMP */
|
||||
}
|
||||
|
||||
@ -628,6 +518,11 @@ npxinit(control)
|
||||
savecrit = critical_enter();
|
||||
npxsave(&dummy);
|
||||
stop_emulating();
|
||||
#ifdef CPU_ENABLE_SSE
|
||||
/* XXX npxsave() doesn't actually initialize the fpu in the SSE case. */
|
||||
if (cpu_fxsr)
|
||||
fninit();
|
||||
#endif
|
||||
fldcw(&control);
|
||||
if (PCPU_GET(curpcb) != NULL)
|
||||
fpusave(&PCPU_GET(curpcb)->pcb_save);
|
||||
|
Loading…
Reference in New Issue
Block a user