15b81b6b3SRodney W. Grimes /*- 25b81b6b3SRodney W. Grimes * Copyright (c) 1990 William Jolitz. 35b81b6b3SRodney W. Grimes * Copyright (c) 1991 The Regents of the University of California. 45b81b6b3SRodney W. Grimes * All rights reserved. 55b81b6b3SRodney W. Grimes * 65b81b6b3SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 75b81b6b3SRodney W. Grimes * modification, are permitted provided that the following conditions 85b81b6b3SRodney W. Grimes * are met: 95b81b6b3SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 105b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 115b81b6b3SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 125b81b6b3SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 135b81b6b3SRodney W. Grimes * documentation and/or other materials provided with the distribution. 145b81b6b3SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 155b81b6b3SRodney W. Grimes * must display the following acknowledgement: 165b81b6b3SRodney W. Grimes * This product includes software developed by the University of 175b81b6b3SRodney W. Grimes * California, Berkeley and its contributors. 185b81b6b3SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 195b81b6b3SRodney W. Grimes * may be used to endorse or promote products derived from this software 205b81b6b3SRodney W. Grimes * without specific prior written permission. 215b81b6b3SRodney W. Grimes * 225b81b6b3SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 235b81b6b3SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 245b81b6b3SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 255b81b6b3SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 265b81b6b3SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 275b81b6b3SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 285b81b6b3SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 295b81b6b3SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 305b81b6b3SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 315b81b6b3SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 325b81b6b3SRodney W. Grimes * SUCH DAMAGE. 335b81b6b3SRodney W. Grimes * 345c644711SRodney W. Grimes * from: @(#)npx.c 7.2 (Berkeley) 5/12/91 35c3aac50fSPeter Wemm * $FreeBSD$ 365b81b6b3SRodney W. Grimes */ 375b81b6b3SRodney W. Grimes 389d146ac5SPeter Wemm #include "opt_cpu.h" 393f2076daSEivind Eklund #include "opt_debug_npx.h" 40d9256606SPeter Wemm #include "opt_math_emulate.h" 4140d8c8daSBruce Evans #include "opt_npx.h" 42a73af3a2SGarrett Wollman 43f540b106SGarrett Wollman #include <sys/param.h> 44f540b106SGarrett Wollman #include <sys/systm.h> 456182fdbdSPeter Wemm #include <sys/bus.h> 463a34a5c3SPoul-Henning Kamp #include <sys/kernel.h> 47fb919e4dSMark Murray #include <sys/lock.h> 48cd59d49dSBruce Evans #include <sys/malloc.h> 496182fdbdSPeter Wemm #include <sys/module.h> 50c1ef8aacSJake Burkholder #include <sys/mutex.h> 51fb919e4dSMark Murray #include <sys/mutex.h> 52fb919e4dSMark Murray #include <sys/proc.h> 53fb919e4dSMark Murray #include <sys/sysctl.h> 546182fdbdSPeter Wemm #include <machine/bus.h> 556182fdbdSPeter Wemm #include <sys/rman.h> 5626add149SBruce Evans #ifdef NPX_DEBUG 57663f1485SBruce Evans #include <sys/syslog.h> 5826add149SBruce Evans #endif 59663f1485SBruce Evans #include <sys/signalvar.h> 6017008f53SBruce Evans #include <sys/user.h> 612f86936aSGarrett Wollman 62e0605ebdSBruce Evans #ifndef SMP 639081eec1SJohn Polstra #include <machine/asmacros.h> 64e0605ebdSBruce Evans #endif 657f47cf2fSBruce Evans #include <machine/cputypes.h> 667f47cf2fSBruce Evans #include <machine/frame.h> 67c673fe98SBruce Evans #include <machine/md_var.h> 685400ed3bSPeter Wemm #include <machine/pcb.h> 697f47cf2fSBruce Evans #include <machine/psl.h> 70e0605ebdSBruce Evans #ifndef SMP 71663f1485SBruce Evans #include <machine/clock.h> 72e0605ebdSBruce Evans #endif 736182fdbdSPeter Wemm #include <machine/resource.h> 74f540b106SGarrett Wollman #include <machine/specialreg.h> 757f47cf2fSBruce Evans #include <machine/segments.h> 762f86936aSGarrett Wollman 77e0605ebdSBruce Evans #ifndef SMP 78f540b106SGarrett Wollman #include <i386/isa/icu.h> 79abfde383SBruce Evans #ifdef PC98 80abfde383SBruce Evans #include <pc98/pc98/pc98.h> 81abfde383SBruce Evans #else 82f540b106SGarrett Wollman #include <i386/isa/isa.h> 83e0605ebdSBruce Evans #endif 84abfde383SBruce Evans #endif 8554f1d0ceSGarrett Wollman #include <isa/isavar.h> 865b81b6b3SRodney W. Grimes 875b81b6b3SRodney W. Grimes /* 885b81b6b3SRodney W. Grimes * 387 and 287 Numeric Coprocessor Extension (NPX) Driver. 895b81b6b3SRodney W. Grimes */ 905b81b6b3SRodney W. Grimes 911fe04850SBruce Evans /* Configuration flags. */ 921fe04850SBruce Evans #define NPX_DISABLE_I586_OPTIMIZED_BCOPY (1 << 0) 931fe04850SBruce Evans #define NPX_DISABLE_I586_OPTIMIZED_BZERO (1 << 1) 941fe04850SBruce Evans #define NPX_DISABLE_I586_OPTIMIZED_COPYIO (1 << 2) 95a7674320SMartin Cracauer #define NPX_PREFER_EMULATOR (1 << 3) 961fe04850SBruce Evans 975b81b6b3SRodney W. Grimes #ifdef __GNUC__ 985b81b6b3SRodney W. Grimes 9937e52b59SBruce Evans #define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr))) 1005b81b6b3SRodney W. Grimes #define fnclex() __asm("fnclex") 1015b81b6b3SRodney W. Grimes #define fninit() __asm("fninit") 1021d37f051SBruce Evans #define fnsave(addr) __asm __volatile("fnsave %0" : "=m" (*(addr))) 1031d37f051SBruce Evans #define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr))) 1041d37f051SBruce Evans #define fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr))) 10537e52b59SBruce Evans #define fp_divide_by_0() __asm("fldz; fld1; fdiv %st,%st(1); fnop") 10637e52b59SBruce Evans #define frstor(addr) __asm("frstor %0" : : "m" (*(addr))) 1073b703181SPeter Wemm #ifdef CPU_ENABLE_SSE 1089d146ac5SPeter Wemm #define fxrstor(addr) __asm("fxrstor %0" : : "m" (*(addr))) 1099d146ac5SPeter Wemm #define fxsave(addr) __asm __volatile("fxsave %0" : "=m" (*(addr))) 1103b703181SPeter Wemm #endif 1115b81b6b3SRodney W. Grimes #define start_emulating() __asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \ 1125b81b6b3SRodney W. Grimes : : "n" (CR0_TS) : "ax") 1135b81b6b3SRodney W. Grimes #define stop_emulating() __asm("clts") 1145b81b6b3SRodney W. Grimes 1155b81b6b3SRodney W. Grimes #else /* not __GNUC__ */ 1165b81b6b3SRodney W. Grimes 1175b81b6b3SRodney W. Grimes void fldcw __P((caddr_t addr)); 1185b81b6b3SRodney W. Grimes void fnclex __P((void)); 1195b81b6b3SRodney W. Grimes void fninit __P((void)); 1205b81b6b3SRodney W. Grimes void fnsave __P((caddr_t addr)); 1215b81b6b3SRodney W. Grimes void fnstcw __P((caddr_t addr)); 1225b81b6b3SRodney W. Grimes void fnstsw __P((caddr_t addr)); 1235b81b6b3SRodney W. Grimes void fp_divide_by_0 __P((void)); 1245b81b6b3SRodney W. Grimes void frstor __P((caddr_t addr)); 1253b703181SPeter Wemm #ifdef CPU_ENABLE_SSE 1269d146ac5SPeter Wemm void fxsave __P((caddr_t addr)); 1279d146ac5SPeter Wemm void fxrstor __P((caddr_t addr)); 1283b703181SPeter Wemm #endif 1295b81b6b3SRodney W. Grimes void start_emulating __P((void)); 1305b81b6b3SRodney W. Grimes void stop_emulating __P((void)); 1315b81b6b3SRodney W. Grimes 1325b81b6b3SRodney W. Grimes #endif /* __GNUC__ */ 1335b81b6b3SRodney W. Grimes 1349d146ac5SPeter Wemm #ifdef CPU_ENABLE_SSE 135b40ce416SJulian Elischer #define GET_FPU_CW(thread) \ 1369d146ac5SPeter Wemm (cpu_fxsr ? \ 137b40ce416SJulian Elischer (thread)->td_pcb->pcb_save.sv_xmm.sv_env.en_cw : \ 138b40ce416SJulian Elischer (thread)->td_pcb->pcb_save.sv_87.sv_env.en_cw) 139b40ce416SJulian Elischer #define GET_FPU_SW(thread) \ 1409d146ac5SPeter Wemm (cpu_fxsr ? \ 141b40ce416SJulian Elischer (thread)->td_pcb->pcb_save.sv_xmm.sv_env.en_sw : \ 142b40ce416SJulian Elischer (thread)->td_pcb->pcb_save.sv_87.sv_env.en_sw) 1439d146ac5SPeter Wemm #define GET_FPU_EXSW_PTR(pcb) \ 1449d146ac5SPeter Wemm (cpu_fxsr ? \ 1459d146ac5SPeter Wemm &(pcb)->pcb_save.sv_xmm.sv_ex_sw : \ 1469d146ac5SPeter Wemm &(pcb)->pcb_save.sv_87.sv_ex_sw) 1479d146ac5SPeter Wemm #else /* CPU_ENABLE_SSE */ 148b40ce416SJulian Elischer #define GET_FPU_CW(thread) \ 149b40ce416SJulian Elischer (thread->td_pcb->pcb_save.sv_87.sv_env.en_cw) 150b40ce416SJulian Elischer #define GET_FPU_SW(thread) \ 151b40ce416SJulian Elischer (thread->td_pcb->pcb_save.sv_87.sv_env.en_sw) 1529d146ac5SPeter Wemm #define GET_FPU_EXSW_PTR(pcb) \ 1539d146ac5SPeter Wemm (&(pcb)->pcb_save.sv_87.sv_ex_sw) 1549d146ac5SPeter Wemm #endif /* CPU_ENABLE_SSE */ 1559d146ac5SPeter Wemm 1565b81b6b3SRodney W. Grimes typedef u_char bool_t; 1575b81b6b3SRodney W. Grimes 1586182fdbdSPeter Wemm static int npx_attach __P((device_t dev)); 159da4113b3SPeter Wemm static void npx_identify __P((driver_t *driver, device_t parent)); 1601c1771cbSBruce Evans #ifndef SMP 1611c1771cbSBruce Evans static void npx_intr __P((void *)); 1621c1771cbSBruce Evans #endif 1636182fdbdSPeter Wemm static int npx_probe __P((device_t dev)); 164a5d00fe9STor Egge static void fpusave __P((union savefpu *)); 165a5d00fe9STor Egge static void fpurstor __P((union savefpu *)); 16617e904e0SPeter Wemm #ifdef I586_CPU_XXX 167cd59d49dSBruce Evans static long timezero __P((const char *funcname, 168cd59d49dSBruce Evans void (*func)(void *buf, size_t len))); 169a4ca0596SDmitrij Tejblum #endif /* I586_CPU */ 1705b81b6b3SRodney W. Grimes 17137e52b59SBruce Evans int hw_float; /* XXX currently just alias for npx_exists */ 1723a34a5c3SPoul-Henning Kamp 1733a34a5c3SPoul-Henning Kamp SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint, 1743a34a5c3SPoul-Henning Kamp CTLFLAG_RD, &hw_float, 0, 1753a34a5c3SPoul-Henning Kamp "Floatingpoint instructions executed in hardware"); 1763a34a5c3SPoul-Henning Kamp 177f1d19042SArchie Cobbs #ifndef SMP 178f1d19042SArchie Cobbs static volatile u_int npx_intrs_while_probing; 179f1d19042SArchie Cobbs static volatile u_int npx_traps_while_probing; 180f1d19042SArchie Cobbs #endif 181b3196e4bSPeter Wemm 1825b81b6b3SRodney W. Grimes static bool_t npx_ex16; 1835b81b6b3SRodney W. Grimes static bool_t npx_exists; 1845b81b6b3SRodney W. Grimes static bool_t npx_irq13; 1855b81b6b3SRodney W. Grimes 1863902c3efSSteve Passe #ifndef SMP 187265e95d9SBruce Evans alias_for_inthand_t probetrap; 18816967563SBruce Evans __asm(" \n\ 18916967563SBruce Evans .text \n\ 19016967563SBruce Evans .p2align 2,0x90 \n\ 191ea2b3e3dSBruce Evans .type " __XSTRING(CNAME(probetrap)) ",@function \n\ 19216967563SBruce Evans " __XSTRING(CNAME(probetrap)) ": \n\ 19316967563SBruce Evans ss \n\ 19416967563SBruce Evans incl " __XSTRING(CNAME(npx_traps_while_probing)) " \n\ 19516967563SBruce Evans fnclex \n\ 19616967563SBruce Evans iret \n\ 1975b81b6b3SRodney W. Grimes "); 1983902c3efSSteve Passe #endif /* SMP */ 1993902c3efSSteve Passe 2005b81b6b3SRodney W. Grimes /* 201da4113b3SPeter Wemm * Identify routine. Create a connection point on our parent for probing. 202da4113b3SPeter Wemm */ 203da4113b3SPeter Wemm static void 204da4113b3SPeter Wemm npx_identify(driver, parent) 205da4113b3SPeter Wemm driver_t *driver; 206da4113b3SPeter Wemm device_t parent; 207da4113b3SPeter Wemm { 208da4113b3SPeter Wemm device_t child; 209da4113b3SPeter Wemm 210da4113b3SPeter Wemm child = BUS_ADD_CHILD(parent, 0, "npx", 0); 211da4113b3SPeter Wemm if (child == NULL) 212da4113b3SPeter Wemm panic("npx_identify"); 213da4113b3SPeter Wemm } 214da4113b3SPeter Wemm 2151c1771cbSBruce Evans #ifndef SMP 2161c1771cbSBruce Evans /* 2171c1771cbSBruce Evans * Do minimal handling of npx interrupts to convert them to traps. 2181c1771cbSBruce Evans */ 2191c1771cbSBruce Evans static void 2201c1771cbSBruce Evans npx_intr(dummy) 2211c1771cbSBruce Evans void *dummy; 2221c1771cbSBruce Evans { 223b40ce416SJulian Elischer struct thread *td; 2241c1771cbSBruce Evans 225265e95d9SBruce Evans #ifndef SMP 226265e95d9SBruce Evans npx_intrs_while_probing++; 227265e95d9SBruce Evans #endif 228265e95d9SBruce Evans 2291c1771cbSBruce Evans /* 2301c1771cbSBruce Evans * The BUSY# latch must be cleared in all cases so that the next 2311c1771cbSBruce Evans * unmasked npx exception causes an interrupt. 2321c1771cbSBruce Evans */ 233abfde383SBruce Evans #ifdef PC98 234abfde383SBruce Evans outb(0xf8, 0); 235abfde383SBruce Evans #else 2361c1771cbSBruce Evans outb(0xf0, 0); 237abfde383SBruce Evans #endif 2381c1771cbSBruce Evans 2391c1771cbSBruce Evans /* 2400bbc8826SJohn Baldwin * fpcurthread is normally non-null here. In that case, schedule an 2411c1771cbSBruce Evans * AST to finish the exception handling in the correct context 242b40ce416SJulian Elischer * (this interrupt may occur after the thread has entered the 2431c1771cbSBruce Evans * kernel via a syscall or an interrupt). Otherwise, the npx 244b40ce416SJulian Elischer * state of the thread that caused this interrupt must have been 2458b8a72eeSWarner Losh * pushed to the thread's pcb, and clearing of the busy latch 2461c1771cbSBruce Evans * above has finished the (essentially null) handling of this 2471c1771cbSBruce Evans * interrupt. Control will eventually return to the instruction 2481c1771cbSBruce Evans * that caused it and it will repeat. We will eventually (usually 2491c1771cbSBruce Evans * soon) win the race to handle the interrupt properly. 2501c1771cbSBruce Evans */ 2510bbc8826SJohn Baldwin td = PCPU_GET(fpcurthread); 252b40ce416SJulian Elischer if (td != NULL) { 253b40ce416SJulian Elischer td->td_pcb->pcb_flags |= PCB_NPXTRAP; 2541c1771cbSBruce Evans mtx_lock_spin(&sched_lock); 255b40ce416SJulian Elischer td->td_kse->ke_flags |= KEF_ASTPENDING; 2561c1771cbSBruce Evans mtx_unlock_spin(&sched_lock); 2571c1771cbSBruce Evans } 2581c1771cbSBruce Evans } 2591c1771cbSBruce Evans #endif /* !SMP */ 2601c1771cbSBruce Evans 261da4113b3SPeter Wemm /* 2625b81b6b3SRodney W. Grimes * Probe routine. Initialize cr0 to give correct behaviour for [f]wait 2635b81b6b3SRodney W. Grimes * whether the device exists or not (XXX should be elsewhere). Set flags 2645b81b6b3SRodney W. Grimes * to tell npxattach() what to do. Modify device struct if npx doesn't 265265e95d9SBruce Evans * need to use interrupts. Return 0 if device exists. 2665b81b6b3SRodney W. Grimes */ 2675b81b6b3SRodney W. Grimes static int 2686182fdbdSPeter Wemm npx_probe(dev) 2696182fdbdSPeter Wemm device_t dev; 2705b81b6b3SRodney W. Grimes { 271f1d19042SArchie Cobbs #ifndef SMP 272265e95d9SBruce Evans struct gate_descriptor save_idt_npxtrap; 273265e95d9SBruce Evans struct resource *ioport_res, *irq_res; 274265e95d9SBruce Evans void *irq_cookie; 275265e95d9SBruce Evans int ioport_rid, irq_num, irq_rid; 27637e52b59SBruce Evans u_short control; 27737e52b59SBruce Evans u_short status; 278265e95d9SBruce Evans 279265e95d9SBruce Evans save_idt_npxtrap = idt[16]; 280265e95d9SBruce Evans setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 281265e95d9SBruce Evans ioport_rid = 0; 282265e95d9SBruce Evans ioport_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &ioport_rid, 283265e95d9SBruce Evans IO_NPX, IO_NPX, IO_NPXSIZE, RF_ACTIVE); 284265e95d9SBruce Evans if (ioport_res == NULL) 285265e95d9SBruce Evans panic("npx: can't get ports"); 286abfde383SBruce Evans #ifdef PC98 287abfde383SBruce Evans if (resource_int_value("npx", 0, "irq", &irq_num) != 0) 288abfde383SBruce Evans irq_num = 8; 289abfde383SBruce Evans #else 290265e95d9SBruce Evans if (resource_int_value("npx", 0, "irq", &irq_num) != 0) 291265e95d9SBruce Evans irq_num = 13; 292abfde383SBruce Evans #endif 293265e95d9SBruce Evans irq_rid = 0; 294265e95d9SBruce Evans irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &ioport_rid, irq_num, 295265e95d9SBruce Evans irq_num, 1, RF_ACTIVE); 296265e95d9SBruce Evans if (irq_res == NULL) 297265e95d9SBruce Evans panic("npx: can't get IRQ"); 298265e95d9SBruce Evans if (bus_setup_intr(dev, irq_res, INTR_TYPE_MISC | INTR_FAST, npx_intr, 299265e95d9SBruce Evans NULL, &irq_cookie) != 0) 300265e95d9SBruce Evans panic("npx: can't create intr"); 301265e95d9SBruce Evans #endif /* !SMP */ 30237e52b59SBruce Evans 3035b81b6b3SRodney W. Grimes /* 3045b81b6b3SRodney W. Grimes * Partially reset the coprocessor, if any. Some BIOS's don't reset 3055b81b6b3SRodney W. Grimes * it after a warm boot. 3065b81b6b3SRodney W. Grimes */ 307abfde383SBruce Evans #ifdef PC98 308abfde383SBruce Evans outb(0xf8,0); 309abfde383SBruce Evans #else 3105b81b6b3SRodney W. Grimes outb(0xf1, 0); /* full reset on some systems, NOP on others */ 3115b81b6b3SRodney W. Grimes outb(0xf0, 0); /* clear BUSY# latch */ 312abfde383SBruce Evans #endif 3135b81b6b3SRodney W. Grimes /* 3145b81b6b3SRodney W. Grimes * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT 3155b81b6b3SRodney W. Grimes * instructions. We must set the CR0_MP bit and use the CR0_TS 3165b81b6b3SRodney W. Grimes * bit to control the trap, because setting the CR0_EM bit does 3175b81b6b3SRodney W. Grimes * not cause WAIT instructions to trap. It's important to trap 3185b81b6b3SRodney W. Grimes * WAIT instructions - otherwise the "wait" variants of no-wait 3195b81b6b3SRodney W. Grimes * control instructions would degenerate to the "no-wait" variants 3205b81b6b3SRodney W. Grimes * after FP context switches but work correctly otherwise. It's 3215b81b6b3SRodney W. Grimes * particularly important to trap WAITs when there is no NPX - 3225b81b6b3SRodney W. Grimes * otherwise the "wait" variants would always degenerate. 3235b81b6b3SRodney W. Grimes * 3245b81b6b3SRodney W. Grimes * Try setting CR0_NE to get correct error reporting on 486DX's. 3255b81b6b3SRodney W. Grimes * Setting it should fail or do nothing on lesser processors. 3265b81b6b3SRodney W. Grimes */ 3275b81b6b3SRodney W. Grimes load_cr0(rcr0() | CR0_MP | CR0_NE); 3285b81b6b3SRodney W. Grimes /* 3295b81b6b3SRodney W. Grimes * But don't trap while we're probing. 3305b81b6b3SRodney W. Grimes */ 3315b81b6b3SRodney W. Grimes stop_emulating(); 3325b81b6b3SRodney W. Grimes /* 3335b81b6b3SRodney W. Grimes * Finish resetting the coprocessor, if any. If there is an error 334265e95d9SBruce Evans * pending, then we may get a bogus IRQ13, but npx_intr() will handle 3355b81b6b3SRodney W. Grimes * it OK. Bogus halts have never been observed, but we enabled 3365b81b6b3SRodney W. Grimes * IRQ13 and cleared the BUSY# latch early to handle them anyway. 3375b81b6b3SRodney W. Grimes */ 3385b81b6b3SRodney W. Grimes fninit(); 3393902c3efSSteve Passe 340265e95d9SBruce Evans device_set_desc(dev, "math processor"); 341265e95d9SBruce Evans 34297bf1787SPeter Wemm #ifdef SMP 343265e95d9SBruce Evans 3443902c3efSSteve Passe /* 3453902c3efSSteve Passe * Exception 16 MUST work for SMP. 3463902c3efSSteve Passe */ 3473902c3efSSteve Passe npx_ex16 = hw_float = npx_exists = 1; 3486182fdbdSPeter Wemm return (0); 3493902c3efSSteve Passe 3506182fdbdSPeter Wemm #else /* !SMP */ 3513902c3efSSteve Passe 3527f3ae831SBruce Evans /* 3537f3ae831SBruce Evans * Don't use fwait here because it might hang. 3547f3ae831SBruce Evans * Don't use fnop here because it usually hangs if there is no FPU. 3557f3ae831SBruce Evans */ 35637e52b59SBruce Evans DELAY(1000); /* wait for any IRQ13 */ 3575b81b6b3SRodney W. Grimes #ifdef DIAGNOSTIC 3585b81b6b3SRodney W. Grimes if (npx_intrs_while_probing != 0) 3595b81b6b3SRodney W. Grimes printf("fninit caused %u bogus npx interrupt(s)\n", 3605b81b6b3SRodney W. Grimes npx_intrs_while_probing); 3615b81b6b3SRodney W. Grimes if (npx_traps_while_probing != 0) 3625b81b6b3SRodney W. Grimes printf("fninit caused %u bogus npx trap(s)\n", 3635b81b6b3SRodney W. Grimes npx_traps_while_probing); 3645b81b6b3SRodney W. Grimes #endif 3655b81b6b3SRodney W. Grimes /* 3665b81b6b3SRodney W. Grimes * Check for a status of mostly zero. 3675b81b6b3SRodney W. Grimes */ 3685b81b6b3SRodney W. Grimes status = 0x5a5a; 3695b81b6b3SRodney W. Grimes fnstsw(&status); 3705b81b6b3SRodney W. Grimes if ((status & 0xb8ff) == 0) { 3715b81b6b3SRodney W. Grimes /* 3725b81b6b3SRodney W. Grimes * Good, now check for a proper control word. 3735b81b6b3SRodney W. Grimes */ 3745b81b6b3SRodney W. Grimes control = 0x5a5a; 3755b81b6b3SRodney W. Grimes fnstcw(&control); 3765b81b6b3SRodney W. Grimes if ((control & 0x1f3f) == 0x033f) { 377501c2393SGarrett Wollman hw_float = npx_exists = 1; 3785b81b6b3SRodney W. Grimes /* 3795b81b6b3SRodney W. Grimes * We have an npx, now divide by 0 to see if exception 3805b81b6b3SRodney W. Grimes * 16 works. 3815b81b6b3SRodney W. Grimes */ 3825b81b6b3SRodney W. Grimes control &= ~(1 << 2); /* enable divide by 0 trap */ 3835b81b6b3SRodney W. Grimes fldcw(&control); 38440d8c8daSBruce Evans #ifdef FPU_ERROR_BROKEN 38540d8c8daSBruce Evans /* 38640d8c8daSBruce Evans * FPU error signal doesn't work on some CPU 38740d8c8daSBruce Evans * accelerator board. 38840d8c8daSBruce Evans */ 38940d8c8daSBruce Evans npx_ex16 = 1; 39040d8c8daSBruce Evans return (0); 39140d8c8daSBruce Evans #endif 3925b81b6b3SRodney W. Grimes npx_traps_while_probing = npx_intrs_while_probing = 0; 3935b81b6b3SRodney W. Grimes fp_divide_by_0(); 3945b81b6b3SRodney W. Grimes if (npx_traps_while_probing != 0) { 3955b81b6b3SRodney W. Grimes /* 3965b81b6b3SRodney W. Grimes * Good, exception 16 works. 3975b81b6b3SRodney W. Grimes */ 3985b81b6b3SRodney W. Grimes npx_ex16 = 1; 399265e95d9SBruce Evans goto no_irq13; 4005b81b6b3SRodney W. Grimes } 4015b81b6b3SRodney W. Grimes if (npx_intrs_while_probing != 0) { 4025b81b6b3SRodney W. Grimes /* 4035b81b6b3SRodney W. Grimes * Bad, we are stuck with IRQ13. 4045b81b6b3SRodney W. Grimes */ 4055b81b6b3SRodney W. Grimes npx_irq13 = 1; 406265e95d9SBruce Evans idt[16] = save_idt_npxtrap; 4076182fdbdSPeter Wemm return (0); 4085b81b6b3SRodney W. Grimes } 4095b81b6b3SRodney W. Grimes /* 4105b81b6b3SRodney W. Grimes * Worse, even IRQ13 is broken. Use emulator. 4115b81b6b3SRodney W. Grimes */ 4125b81b6b3SRodney W. Grimes } 4135b81b6b3SRodney W. Grimes } 4145b81b6b3SRodney W. Grimes /* 4155b81b6b3SRodney W. Grimes * Probe failed, but we want to get to npxattach to initialize the 4165b81b6b3SRodney W. Grimes * emulator and say that it has been installed. XXX handle devices 4175b81b6b3SRodney W. Grimes * that aren't really devices better. 4185b81b6b3SRodney W. Grimes */ 419265e95d9SBruce Evans /* FALLTHROUGH */ 420265e95d9SBruce Evans no_irq13: 421265e95d9SBruce Evans idt[16] = save_idt_npxtrap; 422265e95d9SBruce Evans bus_teardown_intr(dev, irq_res, irq_cookie); 423265e95d9SBruce Evans 424265e95d9SBruce Evans /* 425265e95d9SBruce Evans * XXX hack around brokenness of bus_teardown_intr(). If we left the 426265e95d9SBruce Evans * irq active then we would get it instead of exception 16. 427265e95d9SBruce Evans */ 428265e95d9SBruce Evans INTRDIS(1 << irq_num); 429265e95d9SBruce Evans 430265e95d9SBruce Evans bus_release_resource(dev, SYS_RES_IRQ, irq_rid, irq_res); 431265e95d9SBruce Evans bus_release_resource(dev, SYS_RES_IOPORT, ioport_rid, ioport_res); 4326182fdbdSPeter Wemm return (0); 433265e95d9SBruce Evans 4343902c3efSSteve Passe #endif /* SMP */ 4355b81b6b3SRodney W. Grimes } 4365b81b6b3SRodney W. Grimes 4375b81b6b3SRodney W. Grimes /* 4385b81b6b3SRodney W. Grimes * Attach routine - announce which it is, and wire into system 4395b81b6b3SRodney W. Grimes */ 4405b81b6b3SRodney W. Grimes int 4416182fdbdSPeter Wemm npx_attach(dev) 4426182fdbdSPeter Wemm device_t dev; 4435b81b6b3SRodney W. Grimes { 4446182fdbdSPeter Wemm int flags; 445a7674320SMartin Cracauer 446a7674320SMartin Cracauer if (resource_int_value("npx", 0, "flags", &flags) != 0) 447a7674320SMartin Cracauer flags = 0; 448fe310de8SBruce Evans 449163473ebSPoul-Henning Kamp if (flags) 450a43a8fd7SDoug Rabson device_printf(dev, "flags 0x%x ", flags); 4516182fdbdSPeter Wemm if (npx_irq13) { 452a43a8fd7SDoug Rabson device_printf(dev, "using IRQ 13 interface\n"); 4536182fdbdSPeter Wemm } else { 45437e52b59SBruce Evans #if defined(MATH_EMULATE) || defined(GPL_MATH_EMULATE) 455a7674320SMartin Cracauer if (npx_ex16) { 456a7674320SMartin Cracauer if (!(flags & NPX_PREFER_EMULATOR)) 457a43a8fd7SDoug Rabson device_printf(dev, "INT 16 interface\n"); 458a7674320SMartin Cracauer else { 459a43a8fd7SDoug Rabson device_printf(dev, "FPU exists, but flags request " 460a7674320SMartin Cracauer "emulator\n"); 461a7674320SMartin Cracauer hw_float = npx_exists = 0; 462a7674320SMartin Cracauer } 463a7674320SMartin Cracauer } else if (npx_exists) { 464a43a8fd7SDoug Rabson device_printf(dev, "error reporting broken; using 387 emulator\n"); 4651fe04850SBruce Evans hw_float = npx_exists = 0; 46637e52b59SBruce Evans } else 467a43a8fd7SDoug Rabson device_printf(dev, "387 emulator\n"); 46837e52b59SBruce Evans #else 469a7674320SMartin Cracauer if (npx_ex16) { 470a43a8fd7SDoug Rabson device_printf(dev, "INT 16 interface\n"); 471a7674320SMartin Cracauer if (flags & NPX_PREFER_EMULATOR) { 472a43a8fd7SDoug Rabson device_printf(dev, "emulator requested, but none compiled " 473a7674320SMartin Cracauer "into kernel, using FPU\n"); 474a7674320SMartin Cracauer } 475a7674320SMartin Cracauer } else 476a43a8fd7SDoug Rabson device_printf(dev, "no 387 emulator in kernel and no FPU!\n"); 47737e52b59SBruce Evans #endif 4781fe04850SBruce Evans } 4795b81b6b3SRodney W. Grimes npxinit(__INITIAL_NPXCW__); 4801fe04850SBruce Evans 481adccbaa7SJohn Baldwin #ifdef I586_CPU_XXX 482a7674320SMartin Cracauer if (cpu_class == CPUCLASS_586 && npx_ex16 && npx_exists && 483cd59d49dSBruce Evans timezero("i586_bzero()", i586_bzero) < 484cd59d49dSBruce Evans timezero("bzero()", bzero) * 4 / 5) { 4856182fdbdSPeter Wemm if (!(flags & NPX_DISABLE_I586_OPTIMIZED_BCOPY)) { 4861fe04850SBruce Evans bcopy_vector = i586_bcopy; 4871fe04850SBruce Evans ovbcopy_vector = i586_bcopy; 4881fe04850SBruce Evans } 4896182fdbdSPeter Wemm if (!(flags & NPX_DISABLE_I586_OPTIMIZED_BZERO)) 4901fe04850SBruce Evans bzero = i586_bzero; 4916182fdbdSPeter Wemm if (!(flags & NPX_DISABLE_I586_OPTIMIZED_COPYIO)) { 4921fe04850SBruce Evans copyin_vector = i586_copyin; 4931fe04850SBruce Evans copyout_vector = i586_copyout; 4941fe04850SBruce Evans } 4951fe04850SBruce Evans } 4961fe04850SBruce Evans #endif 4971fe04850SBruce Evans 4986182fdbdSPeter Wemm return (0); /* XXX unused */ 4995b81b6b3SRodney W. Grimes } 5005b81b6b3SRodney W. Grimes 5015b81b6b3SRodney W. Grimes /* 5025b81b6b3SRodney W. Grimes * Initialize floating point unit. 5035b81b6b3SRodney W. Grimes */ 5045b81b6b3SRodney W. Grimes void 5055b81b6b3SRodney W. Grimes npxinit(control) 50637e52b59SBruce Evans u_short control; 5075b81b6b3SRodney W. Grimes { 508e55bc0a0STor Egge static union savefpu dummy; 50970102789SBruce Evans critical_t savecrit; 5105b81b6b3SRodney W. Grimes 5115b81b6b3SRodney W. Grimes if (!npx_exists) 5125b81b6b3SRodney W. Grimes return; 5135b81b6b3SRodney W. Grimes /* 5145b81b6b3SRodney W. Grimes * fninit has the same h/w bugs as fnsave. Use the detoxified 51537e52b59SBruce Evans * fnsave to throw away any junk in the fpu. npxsave() initializes 5160bbc8826SJohn Baldwin * the fpu and sets fpcurthread = NULL as important side effects. 5175b81b6b3SRodney W. Grimes */ 51870102789SBruce Evans savecrit = critical_enter(); 5195b81b6b3SRodney W. Grimes npxsave(&dummy); 5205b81b6b3SRodney W. Grimes stop_emulating(); 5214c8f0aceSTor Egge #ifdef CPU_ENABLE_SSE 5224c8f0aceSTor Egge /* XXX npxsave() doesn't actually initialize the fpu in the SSE case. */ 5234c8f0aceSTor Egge if (cpu_fxsr) 5244c8f0aceSTor Egge fninit(); 5254c8f0aceSTor Egge #endif 5265b81b6b3SRodney W. Grimes fldcw(&control); 527ef73ae4bSJake Burkholder if (PCPU_GET(curpcb) != NULL) 528a5d00fe9STor Egge fpusave(&PCPU_GET(curpcb)->pcb_save); 5295b81b6b3SRodney W. Grimes start_emulating(); 53070102789SBruce Evans critical_exit(savecrit); 5315b81b6b3SRodney W. Grimes } 5325b81b6b3SRodney W. Grimes 5335b81b6b3SRodney W. Grimes /* 5345b81b6b3SRodney W. Grimes * Free coprocessor (if we have it). 5355b81b6b3SRodney W. Grimes */ 5365b81b6b3SRodney W. Grimes void 537b40ce416SJulian Elischer npxexit(td) 538b40ce416SJulian Elischer struct thread *td; 5395b81b6b3SRodney W. Grimes { 54070102789SBruce Evans critical_t savecrit; 5415b81b6b3SRodney W. Grimes 54270102789SBruce Evans savecrit = critical_enter(); 5430bbc8826SJohn Baldwin if (td == PCPU_GET(fpcurthread)) 5449d146ac5SPeter Wemm npxsave(&PCPU_GET(curpcb)->pcb_save); 54570102789SBruce Evans critical_exit(savecrit); 54626add149SBruce Evans #ifdef NPX_DEBUG 547663f1485SBruce Evans if (npx_exists) { 548663f1485SBruce Evans u_int masked_exceptions; 549663f1485SBruce Evans 550ad1b7ffaSPeter Wemm masked_exceptions = PCPU_GET(curpcb)->pcb_save.sv_87.sv_env.en_cw 551ad1b7ffaSPeter Wemm & PCPU_GET(curpcb)->pcb_save.sv_87.sv_env.en_sw & 0x7f; 552663f1485SBruce Evans /* 55326add149SBruce Evans * Log exceptions that would have trapped with the old 55426add149SBruce Evans * control word (overflow, divide by 0, and invalid operand). 555663f1485SBruce Evans */ 556663f1485SBruce Evans if (masked_exceptions & 0x0d) 557663f1485SBruce Evans log(LOG_ERR, 558659209e6SJohn Baldwin "pid %d (%s) exited with masked floating point exceptions 0x%02x\n", 559659209e6SJohn Baldwin td->td_proc->p_pid, td->td_proc->p_comm, 560659209e6SJohn Baldwin masked_exceptions); 5615b81b6b3SRodney W. Grimes } 56226add149SBruce Evans #endif 5635b81b6b3SRodney W. Grimes } 5645b81b6b3SRodney W. Grimes 5655b81b6b3SRodney W. Grimes /* 566a7674320SMartin Cracauer * The following mechanism is used to ensure that the FPE_... value 567a7674320SMartin Cracauer * that is passed as a trapcode to the signal handler of the user 568a7674320SMartin Cracauer * process does not have more than one bit set. 569a7674320SMartin Cracauer * 570a7674320SMartin Cracauer * Multiple bits may be set if the user process modifies the control 571a7674320SMartin Cracauer * word while a status word bit is already set. While this is a sign 572a7674320SMartin Cracauer * of bad coding, we have no choise than to narrow them down to one 573a7674320SMartin Cracauer * bit, since we must not send a trapcode that is not exactly one of 574a7674320SMartin Cracauer * the FPE_ macros. 575a7674320SMartin Cracauer * 576a7674320SMartin Cracauer * The mechanism has a static table with 127 entries. Each combination 577a7674320SMartin Cracauer * of the 7 FPU status word exception bits directly translates to a 578a7674320SMartin Cracauer * position in this table, where a single FPE_... value is stored. 579a7674320SMartin Cracauer * This FPE_... value stored there is considered the "most important" 580a7674320SMartin Cracauer * of the exception bits and will be sent as the signal code. The 581a7674320SMartin Cracauer * precedence of the bits is based upon Intel Document "Numerical 582a7674320SMartin Cracauer * Applications", Chapter "Special Computational Situations". 583a7674320SMartin Cracauer * 584a7674320SMartin Cracauer * The macro to choose one of these values does these steps: 1) Throw 585a7674320SMartin Cracauer * away status word bits that cannot be masked. 2) Throw away the bits 586a7674320SMartin Cracauer * currently masked in the control word, assuming the user isn't 587a7674320SMartin Cracauer * interested in them anymore. 3) Reinsert status word bit 7 (stack 588a7674320SMartin Cracauer * fault) if it is set, which cannot be masked but must be presered. 589a7674320SMartin Cracauer * 4) Use the remaining bits to point into the trapcode table. 590a7674320SMartin Cracauer * 591a7674320SMartin Cracauer * The 6 maskable bits in order of their preference, as stated in the 592a7674320SMartin Cracauer * above referenced Intel manual: 593a7674320SMartin Cracauer * 1 Invalid operation (FP_X_INV) 594a7674320SMartin Cracauer * 1a Stack underflow 595a7674320SMartin Cracauer * 1b Stack overflow 596a7674320SMartin Cracauer * 1c Operand of unsupported format 597a7674320SMartin Cracauer * 1d SNaN operand. 598a7674320SMartin Cracauer * 2 QNaN operand (not an exception, irrelavant here) 599a7674320SMartin Cracauer * 3 Any other invalid-operation not mentioned above or zero divide 600a7674320SMartin Cracauer * (FP_X_INV, FP_X_DZ) 601a7674320SMartin Cracauer * 4 Denormal operand (FP_X_DNML) 602a7674320SMartin Cracauer * 5 Numeric over/underflow (FP_X_OFL, FP_X_UFL) 603784648c6SMartin Cracauer * 6 Inexact result (FP_X_IMP) 604784648c6SMartin Cracauer */ 605a7674320SMartin Cracauer static char fpetable[128] = { 606a7674320SMartin Cracauer 0, 607a7674320SMartin Cracauer FPE_FLTINV, /* 1 - INV */ 608a7674320SMartin Cracauer FPE_FLTUND, /* 2 - DNML */ 609a7674320SMartin Cracauer FPE_FLTINV, /* 3 - INV | DNML */ 610a7674320SMartin Cracauer FPE_FLTDIV, /* 4 - DZ */ 611a7674320SMartin Cracauer FPE_FLTINV, /* 5 - INV | DZ */ 612a7674320SMartin Cracauer FPE_FLTDIV, /* 6 - DNML | DZ */ 613a7674320SMartin Cracauer FPE_FLTINV, /* 7 - INV | DNML | DZ */ 614a7674320SMartin Cracauer FPE_FLTOVF, /* 8 - OFL */ 615a7674320SMartin Cracauer FPE_FLTINV, /* 9 - INV | OFL */ 616a7674320SMartin Cracauer FPE_FLTUND, /* A - DNML | OFL */ 617a7674320SMartin Cracauer FPE_FLTINV, /* B - INV | DNML | OFL */ 618a7674320SMartin Cracauer FPE_FLTDIV, /* C - DZ | OFL */ 619a7674320SMartin Cracauer FPE_FLTINV, /* D - INV | DZ | OFL */ 620a7674320SMartin Cracauer FPE_FLTDIV, /* E - DNML | DZ | OFL */ 621a7674320SMartin Cracauer FPE_FLTINV, /* F - INV | DNML | DZ | OFL */ 622a7674320SMartin Cracauer FPE_FLTUND, /* 10 - UFL */ 623a7674320SMartin Cracauer FPE_FLTINV, /* 11 - INV | UFL */ 624a7674320SMartin Cracauer FPE_FLTUND, /* 12 - DNML | UFL */ 625a7674320SMartin Cracauer FPE_FLTINV, /* 13 - INV | DNML | UFL */ 626a7674320SMartin Cracauer FPE_FLTDIV, /* 14 - DZ | UFL */ 627a7674320SMartin Cracauer FPE_FLTINV, /* 15 - INV | DZ | UFL */ 628a7674320SMartin Cracauer FPE_FLTDIV, /* 16 - DNML | DZ | UFL */ 629a7674320SMartin Cracauer FPE_FLTINV, /* 17 - INV | DNML | DZ | UFL */ 630a7674320SMartin Cracauer FPE_FLTOVF, /* 18 - OFL | UFL */ 631a7674320SMartin Cracauer FPE_FLTINV, /* 19 - INV | OFL | UFL */ 632a7674320SMartin Cracauer FPE_FLTUND, /* 1A - DNML | OFL | UFL */ 633a7674320SMartin Cracauer FPE_FLTINV, /* 1B - INV | DNML | OFL | UFL */ 634a7674320SMartin Cracauer FPE_FLTDIV, /* 1C - DZ | OFL | UFL */ 635a7674320SMartin Cracauer FPE_FLTINV, /* 1D - INV | DZ | OFL | UFL */ 636a7674320SMartin Cracauer FPE_FLTDIV, /* 1E - DNML | DZ | OFL | UFL */ 637a7674320SMartin Cracauer FPE_FLTINV, /* 1F - INV | DNML | DZ | OFL | UFL */ 638a7674320SMartin Cracauer FPE_FLTRES, /* 20 - IMP */ 639a7674320SMartin Cracauer FPE_FLTINV, /* 21 - INV | IMP */ 640a7674320SMartin Cracauer FPE_FLTUND, /* 22 - DNML | IMP */ 641a7674320SMartin Cracauer FPE_FLTINV, /* 23 - INV | DNML | IMP */ 642a7674320SMartin Cracauer FPE_FLTDIV, /* 24 - DZ | IMP */ 643a7674320SMartin Cracauer FPE_FLTINV, /* 25 - INV | DZ | IMP */ 644a7674320SMartin Cracauer FPE_FLTDIV, /* 26 - DNML | DZ | IMP */ 645a7674320SMartin Cracauer FPE_FLTINV, /* 27 - INV | DNML | DZ | IMP */ 646a7674320SMartin Cracauer FPE_FLTOVF, /* 28 - OFL | IMP */ 647a7674320SMartin Cracauer FPE_FLTINV, /* 29 - INV | OFL | IMP */ 648a7674320SMartin Cracauer FPE_FLTUND, /* 2A - DNML | OFL | IMP */ 649a7674320SMartin Cracauer FPE_FLTINV, /* 2B - INV | DNML | OFL | IMP */ 650a7674320SMartin Cracauer FPE_FLTDIV, /* 2C - DZ | OFL | IMP */ 651a7674320SMartin Cracauer FPE_FLTINV, /* 2D - INV | DZ | OFL | IMP */ 652a7674320SMartin Cracauer FPE_FLTDIV, /* 2E - DNML | DZ | OFL | IMP */ 653a7674320SMartin Cracauer FPE_FLTINV, /* 2F - INV | DNML | DZ | OFL | IMP */ 654a7674320SMartin Cracauer FPE_FLTUND, /* 30 - UFL | IMP */ 655a7674320SMartin Cracauer FPE_FLTINV, /* 31 - INV | UFL | IMP */ 656a7674320SMartin Cracauer FPE_FLTUND, /* 32 - DNML | UFL | IMP */ 657a7674320SMartin Cracauer FPE_FLTINV, /* 33 - INV | DNML | UFL | IMP */ 658a7674320SMartin Cracauer FPE_FLTDIV, /* 34 - DZ | UFL | IMP */ 659a7674320SMartin Cracauer FPE_FLTINV, /* 35 - INV | DZ | UFL | IMP */ 660a7674320SMartin Cracauer FPE_FLTDIV, /* 36 - DNML | DZ | UFL | IMP */ 661a7674320SMartin Cracauer FPE_FLTINV, /* 37 - INV | DNML | DZ | UFL | IMP */ 662a7674320SMartin Cracauer FPE_FLTOVF, /* 38 - OFL | UFL | IMP */ 663a7674320SMartin Cracauer FPE_FLTINV, /* 39 - INV | OFL | UFL | IMP */ 664a7674320SMartin Cracauer FPE_FLTUND, /* 3A - DNML | OFL | UFL | IMP */ 665a7674320SMartin Cracauer FPE_FLTINV, /* 3B - INV | DNML | OFL | UFL | IMP */ 666a7674320SMartin Cracauer FPE_FLTDIV, /* 3C - DZ | OFL | UFL | IMP */ 667a7674320SMartin Cracauer FPE_FLTINV, /* 3D - INV | DZ | OFL | UFL | IMP */ 668a7674320SMartin Cracauer FPE_FLTDIV, /* 3E - DNML | DZ | OFL | UFL | IMP */ 669a7674320SMartin Cracauer FPE_FLTINV, /* 3F - INV | DNML | DZ | OFL | UFL | IMP */ 670a7674320SMartin Cracauer FPE_FLTSUB, /* 40 - STK */ 671a7674320SMartin Cracauer FPE_FLTSUB, /* 41 - INV | STK */ 672a7674320SMartin Cracauer FPE_FLTUND, /* 42 - DNML | STK */ 673a7674320SMartin Cracauer FPE_FLTSUB, /* 43 - INV | DNML | STK */ 674a7674320SMartin Cracauer FPE_FLTDIV, /* 44 - DZ | STK */ 675a7674320SMartin Cracauer FPE_FLTSUB, /* 45 - INV | DZ | STK */ 676a7674320SMartin Cracauer FPE_FLTDIV, /* 46 - DNML | DZ | STK */ 677a7674320SMartin Cracauer FPE_FLTSUB, /* 47 - INV | DNML | DZ | STK */ 678a7674320SMartin Cracauer FPE_FLTOVF, /* 48 - OFL | STK */ 679a7674320SMartin Cracauer FPE_FLTSUB, /* 49 - INV | OFL | STK */ 680a7674320SMartin Cracauer FPE_FLTUND, /* 4A - DNML | OFL | STK */ 681a7674320SMartin Cracauer FPE_FLTSUB, /* 4B - INV | DNML | OFL | STK */ 682a7674320SMartin Cracauer FPE_FLTDIV, /* 4C - DZ | OFL | STK */ 683a7674320SMartin Cracauer FPE_FLTSUB, /* 4D - INV | DZ | OFL | STK */ 684a7674320SMartin Cracauer FPE_FLTDIV, /* 4E - DNML | DZ | OFL | STK */ 685a7674320SMartin Cracauer FPE_FLTSUB, /* 4F - INV | DNML | DZ | OFL | STK */ 686a7674320SMartin Cracauer FPE_FLTUND, /* 50 - UFL | STK */ 687a7674320SMartin Cracauer FPE_FLTSUB, /* 51 - INV | UFL | STK */ 688a7674320SMartin Cracauer FPE_FLTUND, /* 52 - DNML | UFL | STK */ 689a7674320SMartin Cracauer FPE_FLTSUB, /* 53 - INV | DNML | UFL | STK */ 690a7674320SMartin Cracauer FPE_FLTDIV, /* 54 - DZ | UFL | STK */ 691a7674320SMartin Cracauer FPE_FLTSUB, /* 55 - INV | DZ | UFL | STK */ 692a7674320SMartin Cracauer FPE_FLTDIV, /* 56 - DNML | DZ | UFL | STK */ 693a7674320SMartin Cracauer FPE_FLTSUB, /* 57 - INV | DNML | DZ | UFL | STK */ 694a7674320SMartin Cracauer FPE_FLTOVF, /* 58 - OFL | UFL | STK */ 695a7674320SMartin Cracauer FPE_FLTSUB, /* 59 - INV | OFL | UFL | STK */ 696a7674320SMartin Cracauer FPE_FLTUND, /* 5A - DNML | OFL | UFL | STK */ 697a7674320SMartin Cracauer FPE_FLTSUB, /* 5B - INV | DNML | OFL | UFL | STK */ 698a7674320SMartin Cracauer FPE_FLTDIV, /* 5C - DZ | OFL | UFL | STK */ 699a7674320SMartin Cracauer FPE_FLTSUB, /* 5D - INV | DZ | OFL | UFL | STK */ 700a7674320SMartin Cracauer FPE_FLTDIV, /* 5E - DNML | DZ | OFL | UFL | STK */ 701a7674320SMartin Cracauer FPE_FLTSUB, /* 5F - INV | DNML | DZ | OFL | UFL | STK */ 702a7674320SMartin Cracauer FPE_FLTRES, /* 60 - IMP | STK */ 703a7674320SMartin Cracauer FPE_FLTSUB, /* 61 - INV | IMP | STK */ 704a7674320SMartin Cracauer FPE_FLTUND, /* 62 - DNML | IMP | STK */ 705a7674320SMartin Cracauer FPE_FLTSUB, /* 63 - INV | DNML | IMP | STK */ 706a7674320SMartin Cracauer FPE_FLTDIV, /* 64 - DZ | IMP | STK */ 707a7674320SMartin Cracauer FPE_FLTSUB, /* 65 - INV | DZ | IMP | STK */ 708a7674320SMartin Cracauer FPE_FLTDIV, /* 66 - DNML | DZ | IMP | STK */ 709a7674320SMartin Cracauer FPE_FLTSUB, /* 67 - INV | DNML | DZ | IMP | STK */ 710a7674320SMartin Cracauer FPE_FLTOVF, /* 68 - OFL | IMP | STK */ 711a7674320SMartin Cracauer FPE_FLTSUB, /* 69 - INV | OFL | IMP | STK */ 712a7674320SMartin Cracauer FPE_FLTUND, /* 6A - DNML | OFL | IMP | STK */ 713a7674320SMartin Cracauer FPE_FLTSUB, /* 6B - INV | DNML | OFL | IMP | STK */ 714a7674320SMartin Cracauer FPE_FLTDIV, /* 6C - DZ | OFL | IMP | STK */ 715a7674320SMartin Cracauer FPE_FLTSUB, /* 6D - INV | DZ | OFL | IMP | STK */ 716a7674320SMartin Cracauer FPE_FLTDIV, /* 6E - DNML | DZ | OFL | IMP | STK */ 717a7674320SMartin Cracauer FPE_FLTSUB, /* 6F - INV | DNML | DZ | OFL | IMP | STK */ 718a7674320SMartin Cracauer FPE_FLTUND, /* 70 - UFL | IMP | STK */ 719a7674320SMartin Cracauer FPE_FLTSUB, /* 71 - INV | UFL | IMP | STK */ 720a7674320SMartin Cracauer FPE_FLTUND, /* 72 - DNML | UFL | IMP | STK */ 721a7674320SMartin Cracauer FPE_FLTSUB, /* 73 - INV | DNML | UFL | IMP | STK */ 722a7674320SMartin Cracauer FPE_FLTDIV, /* 74 - DZ | UFL | IMP | STK */ 723a7674320SMartin Cracauer FPE_FLTSUB, /* 75 - INV | DZ | UFL | IMP | STK */ 724a7674320SMartin Cracauer FPE_FLTDIV, /* 76 - DNML | DZ | UFL | IMP | STK */ 725a7674320SMartin Cracauer FPE_FLTSUB, /* 77 - INV | DNML | DZ | UFL | IMP | STK */ 726a7674320SMartin Cracauer FPE_FLTOVF, /* 78 - OFL | UFL | IMP | STK */ 727a7674320SMartin Cracauer FPE_FLTSUB, /* 79 - INV | OFL | UFL | IMP | STK */ 728a7674320SMartin Cracauer FPE_FLTUND, /* 7A - DNML | OFL | UFL | IMP | STK */ 729a7674320SMartin Cracauer FPE_FLTSUB, /* 7B - INV | DNML | OFL | UFL | IMP | STK */ 730a7674320SMartin Cracauer FPE_FLTDIV, /* 7C - DZ | OFL | UFL | IMP | STK */ 731a7674320SMartin Cracauer FPE_FLTSUB, /* 7D - INV | DZ | OFL | UFL | IMP | STK */ 732a7674320SMartin Cracauer FPE_FLTDIV, /* 7E - DNML | DZ | OFL | UFL | IMP | STK */ 733a7674320SMartin Cracauer FPE_FLTSUB, /* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */ 734a7674320SMartin Cracauer }; 735a7674320SMartin Cracauer 736a7674320SMartin Cracauer /* 73737e52b59SBruce Evans * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE. 7385b81b6b3SRodney W. Grimes * 73937e52b59SBruce Evans * Clearing exceptions is necessary mainly to avoid IRQ13 bugs. We now 74037e52b59SBruce Evans * depend on longjmp() restoring a usable state. Restoring the state 74137e52b59SBruce Evans * or examining it might fail if we didn't clear exceptions. 7425b81b6b3SRodney W. Grimes * 743a7674320SMartin Cracauer * The error code chosen will be one of the FPE_... macros. It will be 744a7674320SMartin Cracauer * sent as the second argument to old BSD-style signal handlers and as 745a7674320SMartin Cracauer * "siginfo_t->si_code" (second argument) to SA_SIGINFO signal handlers. 74637e52b59SBruce Evans * 74737e52b59SBruce Evans * XXX the FP state is not preserved across signal handlers. So signal 74837e52b59SBruce Evans * handlers cannot afford to do FP unless they preserve the state or 74937e52b59SBruce Evans * longjmp() out. Both preserving the state and longjmp()ing may be 75037e52b59SBruce Evans * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable 75137e52b59SBruce Evans * solution for signals other than SIGFPE. 7525b81b6b3SRodney W. Grimes */ 7531c1771cbSBruce Evans int 7541c1771cbSBruce Evans npxtrap() 7555b81b6b3SRodney W. Grimes { 7561c1771cbSBruce Evans critical_t savecrit; 7571c1771cbSBruce Evans u_short control, status; 7589d146ac5SPeter Wemm u_long *exstat; 7595b81b6b3SRodney W. Grimes 76079d4e25bSBruce Evans if (!npx_exists) { 7610bbc8826SJohn Baldwin printf("npxtrap: fpcurthread = %p, curthread = %p, npx_exists = %d\n", 7620bbc8826SJohn Baldwin PCPU_GET(fpcurthread), curthread, npx_exists); 7631c1771cbSBruce Evans panic("npxtrap from nowhere"); 7645b81b6b3SRodney W. Grimes } 7651c1771cbSBruce Evans savecrit = critical_enter(); 7665b81b6b3SRodney W. Grimes 7675b81b6b3SRodney W. Grimes /* 7681c1771cbSBruce Evans * Interrupt handling (for another interrupt) may have pushed the 7691c1771cbSBruce Evans * state to memory. Fetch the relevant parts of the state from 7701c1771cbSBruce Evans * wherever they are. 7715b81b6b3SRodney W. Grimes */ 7720bbc8826SJohn Baldwin if (PCPU_GET(fpcurthread) != curthread) { 773b40ce416SJulian Elischer control = GET_FPU_CW(curthread); 774b40ce416SJulian Elischer status = GET_FPU_SW(curthread); 7755b81b6b3SRodney W. Grimes } else { 7761c1771cbSBruce Evans fnstcw(&control); 7771c1771cbSBruce Evans fnstsw(&status); 7785b81b6b3SRodney W. Grimes } 7791c1771cbSBruce Evans 780b40ce416SJulian Elischer exstat = GET_FPU_EXSW_PTR(curthread->td_pcb); 7819d146ac5SPeter Wemm *exstat = status; 7820bbc8826SJohn Baldwin if (PCPU_GET(fpcurthread) != curthread) 783b40ce416SJulian Elischer GET_FPU_SW(curthread) &= ~0x80bf; 7841c1771cbSBruce Evans else 7851c1771cbSBruce Evans fnclex(); 7861c1771cbSBruce Evans critical_exit(savecrit); 7871c1771cbSBruce Evans return (fpetable[status & ((~control & 0x3f) | 0x40)]); 7885b81b6b3SRodney W. Grimes } 7895b81b6b3SRodney W. Grimes 7905b81b6b3SRodney W. Grimes /* 7915b81b6b3SRodney W. Grimes * Implement device not available (DNA) exception 7925b81b6b3SRodney W. Grimes * 7930bbc8826SJohn Baldwin * It would be better to switch FP context here (if curthread != fpcurthread) 79437e52b59SBruce Evans * and not necessarily for every context switch, but it is too hard to 79537e52b59SBruce Evans * access foreign pcb's. 7965b81b6b3SRodney W. Grimes */ 7975b81b6b3SRodney W. Grimes int 7985b81b6b3SRodney W. Grimes npxdna() 7995b81b6b3SRodney W. Grimes { 8009d146ac5SPeter Wemm u_long *exstat; 8010006681fSJohn Baldwin critical_t s; 80205f6ee66SJake Burkholder 8035b81b6b3SRodney W. Grimes if (!npx_exists) 8045b81b6b3SRodney W. Grimes return (0); 8050bbc8826SJohn Baldwin if (PCPU_GET(fpcurthread) != NULL) { 8060bbc8826SJohn Baldwin printf("npxdna: fpcurthread = %p, curthread = %p\n", 8070bbc8826SJohn Baldwin PCPU_GET(fpcurthread), curthread); 8085b81b6b3SRodney W. Grimes panic("npxdna"); 8095b81b6b3SRodney W. Grimes } 8100006681fSJohn Baldwin s = critical_enter(); 8115b81b6b3SRodney W. Grimes stop_emulating(); 8125b81b6b3SRodney W. Grimes /* 8135b81b6b3SRodney W. Grimes * Record new context early in case frstor causes an IRQ13. 8145b81b6b3SRodney W. Grimes */ 8150bbc8826SJohn Baldwin PCPU_SET(fpcurthread, curthread); 8169d146ac5SPeter Wemm 8179d146ac5SPeter Wemm exstat = GET_FPU_EXSW_PTR(PCPU_GET(curpcb)); 8189d146ac5SPeter Wemm *exstat = 0; 8195b81b6b3SRodney W. Grimes /* 8205b81b6b3SRodney W. Grimes * The following frstor may cause an IRQ13 when the state being 8215b81b6b3SRodney W. Grimes * restored has a pending error. The error will appear to have been 8225b81b6b3SRodney W. Grimes * triggered by the current (npx) user instruction even when that 8235b81b6b3SRodney W. Grimes * instruction is a no-wait instruction that should not trigger an 8245b81b6b3SRodney W. Grimes * error (e.g., fnclex). On at least one 486 system all of the 8255b81b6b3SRodney W. Grimes * no-wait instructions are broken the same as frstor, so our 8265b81b6b3SRodney W. Grimes * treatment does not amplify the breakage. On at least one 8275b81b6b3SRodney W. Grimes * 386/Cyrix 387 system, fnclex works correctly while frstor and 8285b81b6b3SRodney W. Grimes * fnsave are broken, so our treatment breaks fnclex if it is the 8295b81b6b3SRodney W. Grimes * first FPU instruction after a context switch. 8305b81b6b3SRodney W. Grimes */ 831a5d00fe9STor Egge fpurstor(&PCPU_GET(curpcb)->pcb_save); 8320006681fSJohn Baldwin critical_exit(s); 8335b81b6b3SRodney W. Grimes 8345b81b6b3SRodney W. Grimes return (1); 8355b81b6b3SRodney W. Grimes } 8365b81b6b3SRodney W. Grimes 8375b81b6b3SRodney W. Grimes /* 83817008f53SBruce Evans * Wrapper for fnsave instruction, partly to handle hardware bugs. When npx 83917008f53SBruce Evans * exceptions are reported via IRQ13, spurious IRQ13's may be triggered by 84017008f53SBruce Evans * no-wait npx instructions. See the Intel application note AP-578 for 84117008f53SBruce Evans * details. This doesn't cause any additional complications here. IRQ13's 84217008f53SBruce Evans * are inherently asynchronous unless the CPU is frozen to deliver them -- 84317008f53SBruce Evans * one that started in userland may be delivered many instructions later, 84417008f53SBruce Evans * after the process has entered the kernel. It may even be delivered after 84517008f53SBruce Evans * the fnsave here completes. A spurious IRQ13 for the fnsave is handled in 84617008f53SBruce Evans * the same way as a very-late-arriving non-spurious IRQ13 from user mode: 8470bbc8826SJohn Baldwin * it is normally ignored at first because we set fpcurthread to NULL; it is 84817008f53SBruce Evans * normally retriggered in npxdna() after return to user mode. 84917008f53SBruce Evans * 85017008f53SBruce Evans * npxsave() must be called with interrupts disabled, so that it clears 8510bbc8826SJohn Baldwin * fpcurthread atomically with saving the state. We require callers to do the 85217008f53SBruce Evans * disabling, since most callers need to disable interrupts anyway to call 8530bbc8826SJohn Baldwin * npxsave() atomically with checking fpcurthread. 85417008f53SBruce Evans * 85517008f53SBruce Evans * A previous version of npxsave() went to great lengths to excecute fnsave 85617008f53SBruce Evans * with interrupts enabled in case executing it froze the CPU. This case 85717008f53SBruce Evans * can't happen, at least for Intel CPU/NPX's. Spurious IRQ13's don't imply 85817008f53SBruce Evans * spurious freezes. 8595b81b6b3SRodney W. Grimes */ 8605b81b6b3SRodney W. Grimes void 8615b81b6b3SRodney W. Grimes npxsave(addr) 8629d146ac5SPeter Wemm union savefpu *addr; 8635b81b6b3SRodney W. Grimes { 8643902c3efSSteve Passe 8653902c3efSSteve Passe stop_emulating(); 866a5d00fe9STor Egge fpusave(addr); 8679d146ac5SPeter Wemm 8683902c3efSSteve Passe start_emulating(); 8690bbc8826SJohn Baldwin PCPU_SET(fpcurthread, NULL); 8705b81b6b3SRodney W. Grimes } 8715b81b6b3SRodney W. Grimes 8729d146ac5SPeter Wemm static void 873a5d00fe9STor Egge fpusave(addr) 8749d146ac5SPeter Wemm union savefpu *addr; 8759d146ac5SPeter Wemm { 8769d146ac5SPeter Wemm 8773b703181SPeter Wemm #ifdef CPU_ENABLE_SSE 8783b703181SPeter Wemm if (cpu_fxsr) 879e55bc0a0STor Egge fxsave(addr); 8803b703181SPeter Wemm else 8813b703181SPeter Wemm #endif 8823b703181SPeter Wemm fnsave(addr); 8839d146ac5SPeter Wemm } 8849d146ac5SPeter Wemm 8859d146ac5SPeter Wemm static void 886a5d00fe9STor Egge fpurstor(addr) 8879d146ac5SPeter Wemm union savefpu *addr; 8889d146ac5SPeter Wemm { 8893b703181SPeter Wemm 8903b703181SPeter Wemm #ifdef CPU_ENABLE_SSE 8913b703181SPeter Wemm if (cpu_fxsr) 892e55bc0a0STor Egge fxrstor(addr); 8933b703181SPeter Wemm else 8943b703181SPeter Wemm #endif 8953b703181SPeter Wemm frstor(addr); 8969d146ac5SPeter Wemm } 8979d146ac5SPeter Wemm 89817e904e0SPeter Wemm #ifdef I586_CPU_XXX 899cd59d49dSBruce Evans static long 900cd59d49dSBruce Evans timezero(funcname, func) 901cd59d49dSBruce Evans const char *funcname; 902cd59d49dSBruce Evans void (*func) __P((void *buf, size_t len)); 903cd59d49dSBruce Evans 904cd59d49dSBruce Evans { 905cd59d49dSBruce Evans void *buf; 906a6221d8cSDag-Erling Smørgrav #define BUFSIZE 1048576 907cd59d49dSBruce Evans long usec; 908cd59d49dSBruce Evans struct timeval finish, start; 909cd59d49dSBruce Evans 910cd59d49dSBruce Evans buf = malloc(BUFSIZE, M_TEMP, M_NOWAIT); 911cd59d49dSBruce Evans if (buf == NULL) 912cd59d49dSBruce Evans return (BUFSIZE); 913cd59d49dSBruce Evans microtime(&start); 914cd59d49dSBruce Evans (*func)(buf, BUFSIZE); 915cd59d49dSBruce Evans microtime(&finish); 916cd59d49dSBruce Evans usec = 1000000 * (finish.tv_sec - start.tv_sec) + 917cd59d49dSBruce Evans finish.tv_usec - start.tv_usec; 918cd59d49dSBruce Evans if (usec <= 0) 919cd59d49dSBruce Evans usec = 1; 920cd59d49dSBruce Evans if (bootverbose) 92117e904e0SPeter Wemm printf("%s bandwidth = %u kBps\n", funcname, 922a6221d8cSDag-Erling Smørgrav (u_int32_t)(((BUFSIZE >> 10) * 1000000) / usec)); 923cd59d49dSBruce Evans free(buf, M_TEMP); 924cd59d49dSBruce Evans return (usec); 925cd59d49dSBruce Evans } 926cd59d49dSBruce Evans #endif /* I586_CPU */ 927cd59d49dSBruce Evans 9286182fdbdSPeter Wemm static device_method_t npx_methods[] = { 9296182fdbdSPeter Wemm /* Device interface */ 930da4113b3SPeter Wemm DEVMETHOD(device_identify, npx_identify), 9316182fdbdSPeter Wemm DEVMETHOD(device_probe, npx_probe), 9326182fdbdSPeter Wemm DEVMETHOD(device_attach, npx_attach), 9336182fdbdSPeter Wemm DEVMETHOD(device_detach, bus_generic_detach), 9346182fdbdSPeter Wemm DEVMETHOD(device_shutdown, bus_generic_shutdown), 9356182fdbdSPeter Wemm DEVMETHOD(device_suspend, bus_generic_suspend), 9366182fdbdSPeter Wemm DEVMETHOD(device_resume, bus_generic_resume), 9376182fdbdSPeter Wemm 9386182fdbdSPeter Wemm { 0, 0 } 9396182fdbdSPeter Wemm }; 9406182fdbdSPeter Wemm 9416182fdbdSPeter Wemm static driver_t npx_driver = { 9426182fdbdSPeter Wemm "npx", 9436182fdbdSPeter Wemm npx_methods, 9446182fdbdSPeter Wemm 1, /* no softc */ 9456182fdbdSPeter Wemm }; 9466182fdbdSPeter Wemm 9476182fdbdSPeter Wemm static devclass_t npx_devclass; 9486182fdbdSPeter Wemm 9496182fdbdSPeter Wemm /* 9506182fdbdSPeter Wemm * We prefer to attach to the root nexus so that the usual case (exception 16) 9516182fdbdSPeter Wemm * doesn't describe the processor as being `on isa'. 9526182fdbdSPeter Wemm */ 9536182fdbdSPeter Wemm DRIVER_MODULE(npx, nexus, npx_driver, npx_devclass, 0, 0); 95454f1d0ceSGarrett Wollman 95554f1d0ceSGarrett Wollman /* 9565f063c7bSMike Smith * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI. 95754f1d0ceSGarrett Wollman */ 95854f1d0ceSGarrett Wollman static struct isa_pnp_id npxisa_ids[] = { 95954f1d0ceSGarrett Wollman { 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */ 96054f1d0ceSGarrett Wollman { 0 } 96154f1d0ceSGarrett Wollman }; 96254f1d0ceSGarrett Wollman 96354f1d0ceSGarrett Wollman static int 96454f1d0ceSGarrett Wollman npxisa_probe(device_t dev) 96554f1d0ceSGarrett Wollman { 966bb9c06c1SMike Smith int result; 967bb9c06c1SMike Smith if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, npxisa_ids)) <= 0) { 968bb9c06c1SMike Smith device_quiet(dev); 969bb9c06c1SMike Smith } 970bb9c06c1SMike Smith return(result); 97154f1d0ceSGarrett Wollman } 97254f1d0ceSGarrett Wollman 97354f1d0ceSGarrett Wollman static int 97454f1d0ceSGarrett Wollman npxisa_attach(device_t dev) 97554f1d0ceSGarrett Wollman { 97654f1d0ceSGarrett Wollman return (0); 97754f1d0ceSGarrett Wollman } 97854f1d0ceSGarrett Wollman 97954f1d0ceSGarrett Wollman static device_method_t npxisa_methods[] = { 98054f1d0ceSGarrett Wollman /* Device interface */ 98154f1d0ceSGarrett Wollman DEVMETHOD(device_probe, npxisa_probe), 98254f1d0ceSGarrett Wollman DEVMETHOD(device_attach, npxisa_attach), 98354f1d0ceSGarrett Wollman DEVMETHOD(device_detach, bus_generic_detach), 98454f1d0ceSGarrett Wollman DEVMETHOD(device_shutdown, bus_generic_shutdown), 98554f1d0ceSGarrett Wollman DEVMETHOD(device_suspend, bus_generic_suspend), 98654f1d0ceSGarrett Wollman DEVMETHOD(device_resume, bus_generic_resume), 98754f1d0ceSGarrett Wollman 98854f1d0ceSGarrett Wollman { 0, 0 } 98954f1d0ceSGarrett Wollman }; 99054f1d0ceSGarrett Wollman 99154f1d0ceSGarrett Wollman static driver_t npxisa_driver = { 99254f1d0ceSGarrett Wollman "npxisa", 99354f1d0ceSGarrett Wollman npxisa_methods, 99454f1d0ceSGarrett Wollman 1, /* no softc */ 99554f1d0ceSGarrett Wollman }; 99654f1d0ceSGarrett Wollman 99754f1d0ceSGarrett Wollman static devclass_t npxisa_devclass; 99854f1d0ceSGarrett Wollman 99954f1d0ceSGarrett Wollman DRIVER_MODULE(npxisa, isa, npxisa_driver, npxisa_devclass, 0, 0); 100008b00f49SBruce Evans #ifndef PC98 10015f063c7bSMike Smith DRIVER_MODULE(npxisa, acpi, npxisa_driver, npxisa_devclass, 0, 0); 100208b00f49SBruce Evans #endif 100354f1d0ceSGarrett Wollman 1004