npx.c revision 49081
1169689Skan/*-
2169689Skan * Copyright (c) 1990 William Jolitz.
3169689Skan * Copyright (c) 1991 The Regents of the University of California.
4169689Skan * All rights reserved.
5169689Skan *
6169689Skan * Redistribution and use in source and binary forms, with or without
7169689Skan * modification, are permitted provided that the following conditions
8169689Skan * are met:
9169689Skan * 1. Redistributions of source code must retain the above copyright
10169689Skan *    notice, this list of conditions and the following disclaimer.
11169689Skan * 2. Redistributions in binary form must reproduce the above copyright
12169689Skan *    notice, this list of conditions and the following disclaimer in the
13169689Skan *    documentation and/or other materials provided with the distribution.
14169689Skan * 3. All advertising materials mentioning features or use of this software
15169689Skan *    must display the following acknowledgement:
16169689Skan *	This product includes software developed by the University of
17169689Skan *	California, Berkeley and its contributors.
18169689Skan * 4. Neither the name of the University nor the names of its contributors
19169689Skan *    may be used to endorse or promote products derived from this software
20169689Skan *    without specific prior written permission.
21169689Skan *
22169689Skan * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23169689Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24169689Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25169689Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26169689Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27169689Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28169689Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29169689Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30169689Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32169689Skan * SUCH DAMAGE.
33169689Skan *
34169689Skan *	from: @(#)npx.c	7.2 (Berkeley) 5/12/91
35169689Skan *	$Id: npx.c,v 1.73 1999/05/15 17:58:58 peter Exp $
36169689Skan */
37169689Skan
38169689Skan#include "npx.h"
39169689Skan#if NNPX > 0
40169689Skan
41169689Skan#include "opt_debug_npx.h"
42169689Skan#include "opt_math_emulate.h"
43169689Skan
44169689Skan#include <sys/param.h>
45169689Skan#include <sys/systm.h>
46169689Skan#include <sys/bus.h>
47169689Skan#include <sys/kernel.h>
48169689Skan#include <sys/malloc.h>
49169689Skan#include <sys/module.h>
50169689Skan#include <sys/sysctl.h>
51169689Skan#include <sys/proc.h>
52169689Skan#include <machine/bus.h>
53169689Skan#include <sys/rman.h>
54169689Skan#ifdef NPX_DEBUG
55169689Skan#include <sys/syslog.h>
56169689Skan#endif
57169689Skan#include <sys/signalvar.h>
58169689Skan
59169689Skan#ifndef SMP
60169689Skan#include <machine/asmacros.h>
61169689Skan#endif
62169689Skan#include <machine/cputypes.h>
63169689Skan#include <machine/frame.h>
64169689Skan#include <machine/ipl.h>
65169689Skan#include <machine/md_var.h>
66169689Skan#include <machine/pcb.h>
67169689Skan#include <machine/psl.h>
68169689Skan#ifndef SMP
69169689Skan#include <machine/clock.h>
70169689Skan#endif
71169689Skan#include <machine/resource.h>
72169689Skan#include <machine/specialreg.h>
73169689Skan#include <machine/segments.h>
74169689Skan
75169689Skan#ifndef SMP
76169689Skan#include <i386/isa/icu.h>
77169689Skan#include <i386/isa/intr_machdep.h>
78169689Skan#include <i386/isa/isa.h>
79169689Skan#endif
80169689Skan
81169689Skan/*
82169689Skan * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
83169689Skan */
84169689Skan
85169689Skan/* Configuration flags. */
86169689Skan#define	NPX_DISABLE_I586_OPTIMIZED_BCOPY	(1 << 0)
87169689Skan#define	NPX_DISABLE_I586_OPTIMIZED_BZERO	(1 << 1)
88169689Skan#define	NPX_DISABLE_I586_OPTIMIZED_COPYIO	(1 << 2)
89169689Skan#define	NPX_PREFER_EMULATOR			(1 << 3)
90169689Skan
91169689Skan#ifdef	__GNUC__
92169689Skan
93169689Skan#define	fldcw(addr)		__asm("fldcw %0" : : "m" (*(addr)))
94169689Skan#define	fnclex()		__asm("fnclex")
95169689Skan#define	fninit()		__asm("fninit")
96169689Skan#define	fnop()			__asm("fnop")
97169689Skan#define	fnsave(addr)		__asm __volatile("fnsave %0" : "=m" (*(addr)))
98169689Skan#define	fnstcw(addr)		__asm __volatile("fnstcw %0" : "=m" (*(addr)))
99169689Skan#define	fnstsw(addr)		__asm __volatile("fnstsw %0" : "=m" (*(addr)))
100169689Skan#define	fp_divide_by_0()	__asm("fldz; fld1; fdiv %st,%st(1); fnop")
101169689Skan#define	frstor(addr)		__asm("frstor %0" : : "m" (*(addr)))
102169689Skan#define	start_emulating()	__asm("smsw %%ax; orb %0,%%al; lmsw %%ax" \
103169689Skan				      : : "n" (CR0_TS) : "ax")
104169689Skan#define	stop_emulating()	__asm("clts")
105169689Skan
106169689Skan#else	/* not __GNUC__ */
107169689Skan
108169689Skanvoid	fldcw		__P((caddr_t addr));
109169689Skanvoid	fnclex		__P((void));
110169689Skanvoid	fninit		__P((void));
111169689Skanvoid	fnop		__P((void));
112169689Skanvoid	fnsave		__P((caddr_t addr));
113169689Skanvoid	fnstcw		__P((caddr_t addr));
114169689Skanvoid	fnstsw		__P((caddr_t addr));
115169689Skanvoid	fp_divide_by_0	__P((void));
116169689Skanvoid	frstor		__P((caddr_t addr));
117169689Skanvoid	start_emulating	__P((void));
118169689Skanvoid	stop_emulating	__P((void));
119169689Skan
120169689Skan#endif	/* __GNUC__ */
121169689Skan
122169689Skantypedef u_char bool_t;
123169689Skan
124169689Skanstatic	int	npx_attach	__P((device_t dev));
125169689Skan	void	npx_intr	__P((void *));
126169689Skanstatic	int	npx_probe	__P((device_t dev));
127169689Skanstatic	int	npx_probe1	__P((device_t dev));
128169689Skan#ifdef I586_CPU
129169689Skanstatic	long	timezero	__P((const char *funcname,
130169689Skan				     void (*func)(void *buf, size_t len)));
131169689Skan#endif /* I586_CPU */
132169689Skan
133169689Skanint	hw_float;		/* XXX currently just alias for npx_exists */
134169689Skan
135169689SkanSYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
136169689Skan	CTLFLAG_RD, &hw_float, 0,
137169689Skan	"Floatingpoint instructions executed in hardware");
138169689Skan
139169689Skan#ifndef SMP
140169689Skanstatic	u_int			npx0_imask = SWI_CLOCK_MASK;
141169689Skanstatic	struct gate_descriptor	npx_idt_probeintr;
142169689Skanstatic	int			npx_intrno;
143169689Skanstatic	volatile u_int		npx_intrs_while_probing;
144169689Skanstatic	volatile u_int		npx_traps_while_probing;
145169689Skan#endif
146169689Skan
147169689Skanstatic	bool_t			npx_ex16;
148169689Skanstatic	bool_t			npx_exists;
149169689Skanstatic	bool_t			npx_irq13;
150169689Skanstatic	int			npx_irq;	/* irq number */
151169689Skan
152169689Skan#ifndef SMP
153169689Skan/*
154169689Skan * Special interrupt handlers.  Someday intr0-intr15 will be used to count
155169689Skan * interrupts.  We'll still need a special exception 16 handler.  The busy
156169689Skan * latch stuff in probeintr() can be moved to npxprobe().
157169689Skan */
158169689Skaninthand_t probeintr;
159169689Skan__asm("								\n\
160169689Skan	.text							\n\
161169689Skan	.p2align 2,0x90						\n\
162169689Skan	.type	" __XSTRING(CNAME(probeintr)) ",@function	\n\
163169689Skan" __XSTRING(CNAME(probeintr)) ":				\n\
164169689Skan	ss							\n\
165169689Skan	incl	" __XSTRING(CNAME(npx_intrs_while_probing)) "	\n\
166169689Skan	pushl	%eax						\n\
167169689Skan	movb	$0x20,%al	# EOI (asm in strings loses cpp features) \n\
168169689Skan	outb	%al,$0xa0	# IO_ICU2			\n\
169169689Skan	outb	%al,$0x20	# IO_ICU1			\n\
170169689Skan	movb	$0,%al						\n\
171169689Skan	outb	%al,$0xf0	# clear BUSY# latch		\n\
172169689Skan	popl	%eax						\n\
173169689Skan	iret							\n\
174169689Skan");
175169689Skan
176169689Skaninthand_t probetrap;
177169689Skan__asm("								\n\
178169689Skan	.text							\n\
179169689Skan	.p2align 2,0x90						\n\
180169689Skan	.type	" __XSTRING(CNAME(probetrap)) ",@function	\n\
181169689Skan" __XSTRING(CNAME(probetrap)) ":				\n\
182169689Skan	ss							\n\
183169689Skan	incl	" __XSTRING(CNAME(npx_traps_while_probing)) "	\n\
184169689Skan	fnclex							\n\
185169689Skan	iret							\n\
186169689Skan");
187169689Skan#endif /* SMP */
188169689Skan
189169689Skan/*
190169689Skan * Probe routine.  Initialize cr0 to give correct behaviour for [f]wait
191169689Skan * whether the device exists or not (XXX should be elsewhere).  Set flags
192169689Skan * to tell npxattach() what to do.  Modify device struct if npx doesn't
193169689Skan * need to use interrupts.  Return 1 if device exists.
194169689Skan */
195169689Skanstatic int
196169689Skannpx_probe(dev)
197169689Skan	device_t dev;
198169689Skan{
199169689Skan#ifdef SMP
200169689Skan
201169689Skan	if (resource_int_value("npx", 0, "irq", &npx_irq) != 0)
202169689Skan		npx_irq = 13;
203169689Skan	return npx_probe1(dev);
204169689Skan
205169689Skan#else /* SMP */
206169689Skan
207169689Skan	int	result;
208169689Skan	u_long	save_eflags;
209169689Skan	u_char	save_icu1_mask;
210169689Skan	u_char	save_icu2_mask;
211169689Skan	struct	gate_descriptor save_idt_npxintr;
212169689Skan	struct	gate_descriptor save_idt_npxtrap;
213169689Skan	/*
214169689Skan	 * This routine is now just a wrapper for npxprobe1(), to install
215169689Skan	 * special npx interrupt and trap handlers, to enable npx interrupts
216169689Skan	 * and to disable other interrupts.  Someday isa_configure() will
217169689Skan	 * install suitable handlers and run with interrupts enabled so we
218169689Skan	 * won't need to do so much here.
219169689Skan	 */
220169689Skan	if (resource_int_value("npx", 0, "irq", &npx_irq) != 0)
221169689Skan		npx_irq = 13;
222169689Skan	npx_intrno = NRSVIDT + npx_irq;
223169689Skan	save_eflags = read_eflags();
224169689Skan	disable_intr();
225169689Skan	save_icu1_mask = inb(IO_ICU1 + 1);
226169689Skan	save_icu2_mask = inb(IO_ICU2 + 1);
227169689Skan	save_idt_npxintr = idt[npx_intrno];
228169689Skan	save_idt_npxtrap = idt[16];
229169689Skan	outb(IO_ICU1 + 1, ~IRQ_SLAVE);
230169689Skan	outb(IO_ICU2 + 1, ~(1 << (npx_irq - 8)));
231169689Skan	setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
232169689Skan	setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
233169689Skan	npx_idt_probeintr = idt[npx_intrno];
234169689Skan	enable_intr();
235169689Skan	result = npx_probe1(dev);
236169689Skan	disable_intr();
237169689Skan	outb(IO_ICU1 + 1, save_icu1_mask);
238169689Skan	outb(IO_ICU2 + 1, save_icu2_mask);
239169689Skan	idt[npx_intrno] = save_idt_npxintr;
240169689Skan	idt[16] = save_idt_npxtrap;
241169689Skan	write_eflags(save_eflags);
242169689Skan	return (result);
243169689Skan
244169689Skan#endif /* SMP */
245169689Skan}
246169689Skan
247169689Skanstatic int
248169689Skannpx_probe1(dev)
249169689Skan	device_t dev;
250169689Skan{
251169689Skan#ifndef SMP
252169689Skan	u_short control;
253169689Skan	u_short status;
254169689Skan#endif
255169689Skan
256169689Skan	/*
257169689Skan	 * Partially reset the coprocessor, if any.  Some BIOS's don't reset
258169689Skan	 * it after a warm boot.
259169689Skan	 */
260169689Skan	outb(0xf1, 0);		/* full reset on some systems, NOP on others */
261169689Skan	outb(0xf0, 0);		/* clear BUSY# latch */
262169689Skan	/*
263169689Skan	 * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
264169689Skan	 * instructions.  We must set the CR0_MP bit and use the CR0_TS
265169689Skan	 * bit to control the trap, because setting the CR0_EM bit does
266169689Skan	 * not cause WAIT instructions to trap.  It's important to trap
267169689Skan	 * WAIT instructions - otherwise the "wait" variants of no-wait
268169689Skan	 * control instructions would degenerate to the "no-wait" variants
269169689Skan	 * after FP context switches but work correctly otherwise.  It's
270169689Skan	 * particularly important to trap WAITs when there is no NPX -
271169689Skan	 * otherwise the "wait" variants would always degenerate.
272169689Skan	 *
273169689Skan	 * Try setting CR0_NE to get correct error reporting on 486DX's.
274169689Skan	 * Setting it should fail or do nothing on lesser processors.
275169689Skan	 */
276169689Skan	load_cr0(rcr0() | CR0_MP | CR0_NE);
277169689Skan	/*
278169689Skan	 * But don't trap while we're probing.
279169689Skan	 */
280169689Skan	stop_emulating();
281169689Skan	/*
282169689Skan	 * Finish resetting the coprocessor, if any.  If there is an error
283169689Skan	 * pending, then we may get a bogus IRQ13, but probeintr() will handle
284169689Skan	 * it OK.  Bogus halts have never been observed, but we enabled
285169689Skan	 * IRQ13 and cleared the BUSY# latch early to handle them anyway.
286169689Skan	 */
287169689Skan	fninit();
288169689Skan
289169689Skan#ifdef SMP
290169689Skan	/*
291169689Skan	 * Exception 16 MUST work for SMP.
292169689Skan	 */
293169689Skan	npx_irq13 = 0;
294169689Skan	npx_ex16 = hw_float = npx_exists = 1;
295169689Skan	device_set_desc(dev, "math processor");
296169689Skan	return (0);
297169689Skan
298169689Skan#else /* !SMP */
299169689Skan	device_set_desc(dev, "math processor");
300169689Skan
301169689Skan	/*
302169689Skan	 * Don't use fwait here because it might hang.
303169689Skan	 * Don't use fnop here because it usually hangs if there is no FPU.
304169689Skan	 */
305169689Skan	DELAY(1000);		/* wait for any IRQ13 */
306169689Skan#ifdef DIAGNOSTIC
307169689Skan	if (npx_intrs_while_probing != 0)
308169689Skan		printf("fninit caused %u bogus npx interrupt(s)\n",
309169689Skan		       npx_intrs_while_probing);
310169689Skan	if (npx_traps_while_probing != 0)
311169689Skan		printf("fninit caused %u bogus npx trap(s)\n",
312169689Skan		       npx_traps_while_probing);
313169689Skan#endif
314169689Skan	/*
315169689Skan	 * Check for a status of mostly zero.
316169689Skan	 */
317169689Skan	status = 0x5a5a;
318169689Skan	fnstsw(&status);
319169689Skan	if ((status & 0xb8ff) == 0) {
320169689Skan		/*
321169689Skan		 * Good, now check for a proper control word.
322169689Skan		 */
323169689Skan		control = 0x5a5a;
324169689Skan		fnstcw(&control);
325169689Skan		if ((control & 0x1f3f) == 0x033f) {
326169689Skan			hw_float = npx_exists = 1;
327169689Skan			/*
328169689Skan			 * We have an npx, now divide by 0 to see if exception
329169689Skan			 * 16 works.
330169689Skan			 */
331169689Skan			control &= ~(1 << 2);	/* enable divide by 0 trap */
332169689Skan			fldcw(&control);
333169689Skan			npx_traps_while_probing = npx_intrs_while_probing = 0;
334169689Skan			fp_divide_by_0();
335169689Skan			if (npx_traps_while_probing != 0) {
336169689Skan				/*
337169689Skan				 * Good, exception 16 works.
338169689Skan				 */
339169689Skan				npx_ex16 = 1;
340169689Skan				return (0);
341169689Skan			}
342169689Skan			if (npx_intrs_while_probing != 0) {
343169689Skan				int	rid;
344169689Skan				struct	resource *r;
345169689Skan				void	*intr;
346169689Skan				/*
347169689Skan				 * Bad, we are stuck with IRQ13.
348169689Skan				 */
349169689Skan				npx_irq13 = 1;
350169689Skan				/*
351169689Skan				 * npxattach would be too late to set npx0_imask
352169689Skan				 */
353169689Skan				npx0_imask |= (1 << npx_irq);
354169689Skan
355169689Skan				/*
356169689Skan				 * We allocate these resources permanently,
357169689Skan				 * so there is no need to keep track of them.
358169689Skan				 */
359169689Skan				rid = 0;
360169689Skan				r = bus_alloc_resource(dev, SYS_RES_IOPORT,
361169689Skan						       &rid, IO_NPX, IO_NPX,
362169689Skan						       IO_NPXSIZE, RF_ACTIVE);
363169689Skan				if (r == 0)
364169689Skan					panic("npx: can't get ports");
365169689Skan				rid = 0;
366169689Skan				r = bus_alloc_resource(dev, SYS_RES_IRQ,
367169689Skan						       &rid, npx_irq, npx_irq,
368169689Skan						       1, RF_ACTIVE);
369169689Skan				if (r == 0)
370169689Skan					panic("npx: can't get IRQ");
371169689Skan				BUS_SETUP_INTR(device_get_parent(dev),
372169689Skan					       dev, r, INTR_TYPE_MISC,
373169689Skan					       npx_intr, 0, &intr);
374169689Skan				if (intr == 0)
375169689Skan					panic("npx: can't create intr");
376169689Skan
377169689Skan				return (0);
378169689Skan			}
379169689Skan			/*
380169689Skan			 * Worse, even IRQ13 is broken.  Use emulator.
381169689Skan			 */
382169689Skan		}
383169689Skan	}
384169689Skan	/*
385169689Skan	 * Probe failed, but we want to get to npxattach to initialize the
386169689Skan	 * emulator and say that it has been installed.  XXX handle devices
387169689Skan	 * that aren't really devices better.
388169689Skan	 */
389169689Skan	return (0);
390169689Skan#endif /* SMP */
391169689Skan}
392169689Skan
393169689Skan/*
394169689Skan * Attach routine - announce which it is, and wire into system
395169689Skan */
396169689Skanint
397169689Skannpx_attach(dev)
398169689Skan	device_t dev;
399169689Skan{
400169689Skan	int flags;
401169689Skan
402169689Skan	if (resource_int_value("npx", 0, "flags", &flags) != 0)
403169689Skan		flags = 0;
404169689Skan
405169689Skan	device_print_prettyname(dev);
406169689Skan	if (npx_irq13) {
407169689Skan		printf("using IRQ 13 interface\n");
408169689Skan	} else {
409169689Skan#if defined(MATH_EMULATE) || defined(GPL_MATH_EMULATE)
410169689Skan		if (npx_ex16) {
411169689Skan			if (!(flags & NPX_PREFER_EMULATOR))
412169689Skan				printf("INT 16 interface\n");
413169689Skan			else {
414169689Skan				printf("FPU exists, but flags request "
415169689Skan				    "emulator\n");
416169689Skan				hw_float = npx_exists = 0;
417169689Skan			}
418169689Skan		} else if (npx_exists) {
419169689Skan			printf("error reporting broken; using 387 emulator\n");
420169689Skan			hw_float = npx_exists = 0;
421169689Skan		} else
422169689Skan			printf("387 emulator\n");
423169689Skan#else
424169689Skan		if (npx_ex16) {
425169689Skan			printf("INT 16 interface\n");
426169689Skan			if (flags & NPX_PREFER_EMULATOR) {
427169689Skan				printf("emulator requested, but none compiled "
428169689Skan				    "into kernel, using FPU\n");
429169689Skan			}
430169689Skan		} else
431169689Skan			printf("no 387 emulator in kernel and no FPU!\n");
432169689Skan#endif
433169689Skan	}
434169689Skan	npxinit(__INITIAL_NPXCW__);
435169689Skan
436169689Skan#ifdef I586_CPU
437169689Skan	if (cpu_class == CPUCLASS_586 && npx_ex16 && npx_exists &&
438169689Skan	    timezero("i586_bzero()", i586_bzero) <
439169689Skan	    timezero("bzero()", bzero) * 4 / 5) {
440169689Skan		if (!(flags & NPX_DISABLE_I586_OPTIMIZED_BCOPY)) {
441169689Skan			bcopy_vector = i586_bcopy;
442169689Skan			ovbcopy_vector = i586_bcopy;
443169689Skan		}
444169689Skan		if (!(flags & NPX_DISABLE_I586_OPTIMIZED_BZERO))
445169689Skan			bzero = i586_bzero;
446169689Skan		if (!(flags & NPX_DISABLE_I586_OPTIMIZED_COPYIO)) {
447169689Skan			copyin_vector = i586_copyin;
448169689Skan			copyout_vector = i586_copyout;
449169689Skan		}
450169689Skan	}
451169689Skan#endif
452169689Skan
453169689Skan	return (0);		/* XXX unused */
454169689Skan}
455169689Skan
456169689Skan/*
457169689Skan * Initialize floating point unit.
458169689Skan */
459169689Skanvoid
460169689Skannpxinit(control)
461169689Skan	u_short control;
462169689Skan{
463169689Skan	struct save87 dummy;
464169689Skan
465169689Skan	if (!npx_exists)
466169689Skan		return;
467169689Skan	/*
468169689Skan	 * fninit has the same h/w bugs as fnsave.  Use the detoxified
469169689Skan	 * fnsave to throw away any junk in the fpu.  npxsave() initializes
470169689Skan	 * the fpu and sets npxproc = NULL as important side effects.
471169689Skan	 */
472169689Skan	npxsave(&dummy);
473169689Skan	stop_emulating();
474169689Skan	fldcw(&control);
475169689Skan	if (curpcb != NULL)
476169689Skan		fnsave(&curpcb->pcb_savefpu);
477169689Skan	start_emulating();
478169689Skan}
479169689Skan
480169689Skan/*
481169689Skan * Free coprocessor (if we have it).
482169689Skan */
483169689Skanvoid
484169689Skannpxexit(p)
485169689Skan	struct proc *p;
486169689Skan{
487169689Skan
488169689Skan	if (p == npxproc)
489169689Skan		npxsave(&curpcb->pcb_savefpu);
490169689Skan#ifdef NPX_DEBUG
491169689Skan	if (npx_exists) {
492169689Skan		u_int	masked_exceptions;
493169689Skan
494169689Skan		masked_exceptions = curpcb->pcb_savefpu.sv_env.en_cw
495169689Skan				    & curpcb->pcb_savefpu.sv_env.en_sw & 0x7f;
496169689Skan		/*
497169689Skan		 * Log exceptions that would have trapped with the old
498169689Skan		 * control word (overflow, divide by 0, and invalid operand).
499169689Skan		 */
500169689Skan		if (masked_exceptions & 0x0d)
501169689Skan			log(LOG_ERR,
502169689Skan	"pid %d (%s) exited with masked floating point exceptions 0x%02x\n",
503169689Skan			    p->p_pid, p->p_comm, masked_exceptions);
504169689Skan	}
505169689Skan#endif
506169689Skan}
507169689Skan
508169689Skan/*
509169689Skan * The following mechanism is used to ensure that the FPE_... value
510169689Skan * that is passed as a trapcode to the signal handler of the user
511169689Skan * process does not have more than one bit set.
512169689Skan *
513169689Skan * Multiple bits may be set if the user process modifies the control
514169689Skan * word while a status word bit is already set. While this is a sign
515169689Skan * of bad coding, we have no choise than to narrow them down to one
516169689Skan * bit, since we must not send a trapcode that is not exactly one of
517169689Skan * the FPE_ macros.
518169689Skan *
519169689Skan * The mechanism has a static table with 127 entries. Each combination
520169689Skan * of the 7 FPU status word exception bits directly translates to a
521169689Skan * position in this table, where a single FPE_... value is stored.
522169689Skan * This FPE_... value stored there is considered the "most important"
523169689Skan * of the exception bits and will be sent as the signal code. The
524169689Skan * precedence of the bits is based upon Intel Document "Numerical
525169689Skan * Applications", Chapter "Special Computational Situations".
526169689Skan *
527169689Skan * The macro to choose one of these values does these steps: 1) Throw
528169689Skan * away status word bits that cannot be masked. 2) Throw away the bits
529169689Skan * currently masked in the control word, assuming the user isn't
530169689Skan * interested in them anymore. 3) Reinsert status word bit 7 (stack
531169689Skan * fault) if it is set, which cannot be masked but must be presered.
532169689Skan * 4) Use the remaining bits to point into the trapcode table.
533169689Skan *
534169689Skan * The 6 maskable bits in order of their preference, as stated in the
535169689Skan * above referenced Intel manual:
536169689Skan * 1  Invalid operation (FP_X_INV)
537169689Skan * 1a   Stack underflow
538169689Skan * 1b   Stack overflow
539169689Skan * 1c   Operand of unsupported format
540169689Skan * 1d   SNaN operand.
541169689Skan * 2  QNaN operand (not an exception, irrelavant here)
542169689Skan * 3  Any other invalid-operation not mentioned above or zero divide
543169689Skan *      (FP_X_INV, FP_X_DZ)
544169689Skan * 4  Denormal operand (FP_X_DNML)
545169689Skan * 5  Numeric over/underflow (FP_X_OFL, FP_X_UFL)
546169689Skan * 6  Inexact result (FP_X_IMP) */
547169689Skan
548169689Skanstatic char fpetable[128] = {
549169689Skan	0,
550169689Skan	FPE_FLTINV, /*  1 - INV */
551169689Skan	FPE_FLTUND, /*  2 - DNML */
552169689Skan	FPE_FLTINV, /*  3 - INV | DNML */
553169689Skan	FPE_FLTDIV, /*  4 - DZ */
554169689Skan	FPE_FLTINV, /*  5 - INV | DZ */
555169689Skan	FPE_FLTDIV, /*  6 - DNML | DZ */
556169689Skan	FPE_FLTINV, /*  7 - INV | DNML | DZ */
557169689Skan	FPE_FLTOVF, /*  8 - OFL */
558169689Skan	FPE_FLTINV, /*  9 - INV | OFL */
559169689Skan	FPE_FLTUND, /*  A - DNML | OFL */
560169689Skan	FPE_FLTINV, /*  B - INV | DNML | OFL */
561169689Skan	FPE_FLTDIV, /*  C - DZ | OFL */
562169689Skan	FPE_FLTINV, /*  D - INV | DZ | OFL */
563169689Skan	FPE_FLTDIV, /*  E - DNML | DZ | OFL */
564169689Skan	FPE_FLTINV, /*  F - INV | DNML | DZ | OFL */
565169689Skan	FPE_FLTUND, /* 10 - UFL */
566169689Skan	FPE_FLTINV, /* 11 - INV | UFL */
567169689Skan	FPE_FLTUND, /* 12 - DNML | UFL */
568169689Skan	FPE_FLTINV, /* 13 - INV | DNML | UFL */
569169689Skan	FPE_FLTDIV, /* 14 - DZ | UFL */
570169689Skan	FPE_FLTINV, /* 15 - INV | DZ | UFL */
571169689Skan	FPE_FLTDIV, /* 16 - DNML | DZ | UFL */
572169689Skan	FPE_FLTINV, /* 17 - INV | DNML | DZ | UFL */
573169689Skan	FPE_FLTOVF, /* 18 - OFL | UFL */
574169689Skan	FPE_FLTINV, /* 19 - INV | OFL | UFL */
575169689Skan	FPE_FLTUND, /* 1A - DNML | OFL | UFL */
576169689Skan	FPE_FLTINV, /* 1B - INV | DNML | OFL | UFL */
577169689Skan	FPE_FLTDIV, /* 1C - DZ | OFL | UFL */
578169689Skan	FPE_FLTINV, /* 1D - INV | DZ | OFL | UFL */
579169689Skan	FPE_FLTDIV, /* 1E - DNML | DZ | OFL | UFL */
580169689Skan	FPE_FLTINV, /* 1F - INV | DNML | DZ | OFL | UFL */
581169689Skan	FPE_FLTRES, /* 20 - IMP */
582169689Skan	FPE_FLTINV, /* 21 - INV | IMP */
583169689Skan	FPE_FLTUND, /* 22 - DNML | IMP */
584169689Skan	FPE_FLTINV, /* 23 - INV | DNML | IMP */
585169689Skan	FPE_FLTDIV, /* 24 - DZ | IMP */
586169689Skan	FPE_FLTINV, /* 25 - INV | DZ | IMP */
587169689Skan	FPE_FLTDIV, /* 26 - DNML | DZ | IMP */
588169689Skan	FPE_FLTINV, /* 27 - INV | DNML | DZ | IMP */
589169689Skan	FPE_FLTOVF, /* 28 - OFL | IMP */
590169689Skan	FPE_FLTINV, /* 29 - INV | OFL | IMP */
591169689Skan	FPE_FLTUND, /* 2A - DNML | OFL | IMP */
592169689Skan	FPE_FLTINV, /* 2B - INV | DNML | OFL | IMP */
593169689Skan	FPE_FLTDIV, /* 2C - DZ | OFL | IMP */
594169689Skan	FPE_FLTINV, /* 2D - INV | DZ | OFL | IMP */
595169689Skan	FPE_FLTDIV, /* 2E - DNML | DZ | OFL | IMP */
596169689Skan	FPE_FLTINV, /* 2F - INV | DNML | DZ | OFL | IMP */
597169689Skan	FPE_FLTUND, /* 30 - UFL | IMP */
598169689Skan	FPE_FLTINV, /* 31 - INV | UFL | IMP */
599169689Skan	FPE_FLTUND, /* 32 - DNML | UFL | IMP */
600169689Skan	FPE_FLTINV, /* 33 - INV | DNML | UFL | IMP */
601169689Skan	FPE_FLTDIV, /* 34 - DZ | UFL | IMP */
602169689Skan	FPE_FLTINV, /* 35 - INV | DZ | UFL | IMP */
603169689Skan	FPE_FLTDIV, /* 36 - DNML | DZ | UFL | IMP */
604169689Skan	FPE_FLTINV, /* 37 - INV | DNML | DZ | UFL | IMP */
605169689Skan	FPE_FLTOVF, /* 38 - OFL | UFL | IMP */
606169689Skan	FPE_FLTINV, /* 39 - INV | OFL | UFL | IMP */
607169689Skan	FPE_FLTUND, /* 3A - DNML | OFL | UFL | IMP */
608169689Skan	FPE_FLTINV, /* 3B - INV | DNML | OFL | UFL | IMP */
609169689Skan	FPE_FLTDIV, /* 3C - DZ | OFL | UFL | IMP */
610169689Skan	FPE_FLTINV, /* 3D - INV | DZ | OFL | UFL | IMP */
611169689Skan	FPE_FLTDIV, /* 3E - DNML | DZ | OFL | UFL | IMP */
612169689Skan	FPE_FLTINV, /* 3F - INV | DNML | DZ | OFL | UFL | IMP */
613169689Skan	FPE_FLTSUB, /* 40 - STK */
614169689Skan	FPE_FLTSUB, /* 41 - INV | STK */
615169689Skan	FPE_FLTUND, /* 42 - DNML | STK */
616169689Skan	FPE_FLTSUB, /* 43 - INV | DNML | STK */
617169689Skan	FPE_FLTDIV, /* 44 - DZ | STK */
618169689Skan	FPE_FLTSUB, /* 45 - INV | DZ | STK */
619169689Skan	FPE_FLTDIV, /* 46 - DNML | DZ | STK */
620169689Skan	FPE_FLTSUB, /* 47 - INV | DNML | DZ | STK */
621169689Skan	FPE_FLTOVF, /* 48 - OFL | STK */
622169689Skan	FPE_FLTSUB, /* 49 - INV | OFL | STK */
623169689Skan	FPE_FLTUND, /* 4A - DNML | OFL | STK */
624169689Skan	FPE_FLTSUB, /* 4B - INV | DNML | OFL | STK */
625169689Skan	FPE_FLTDIV, /* 4C - DZ | OFL | STK */
626169689Skan	FPE_FLTSUB, /* 4D - INV | DZ | OFL | STK */
627169689Skan	FPE_FLTDIV, /* 4E - DNML | DZ | OFL | STK */
628169689Skan	FPE_FLTSUB, /* 4F - INV | DNML | DZ | OFL | STK */
629169689Skan	FPE_FLTUND, /* 50 - UFL | STK */
630169689Skan	FPE_FLTSUB, /* 51 - INV | UFL | STK */
631169689Skan	FPE_FLTUND, /* 52 - DNML | UFL | STK */
632169689Skan	FPE_FLTSUB, /* 53 - INV | DNML | UFL | STK */
633169689Skan	FPE_FLTDIV, /* 54 - DZ | UFL | STK */
634169689Skan	FPE_FLTSUB, /* 55 - INV | DZ | UFL | STK */
635169689Skan	FPE_FLTDIV, /* 56 - DNML | DZ | UFL | STK */
636169689Skan	FPE_FLTSUB, /* 57 - INV | DNML | DZ | UFL | STK */
637169689Skan	FPE_FLTOVF, /* 58 - OFL | UFL | STK */
638169689Skan	FPE_FLTSUB, /* 59 - INV | OFL | UFL | STK */
639169689Skan	FPE_FLTUND, /* 5A - DNML | OFL | UFL | STK */
640169689Skan	FPE_FLTSUB, /* 5B - INV | DNML | OFL | UFL | STK */
641169689Skan	FPE_FLTDIV, /* 5C - DZ | OFL | UFL | STK */
642169689Skan	FPE_FLTSUB, /* 5D - INV | DZ | OFL | UFL | STK */
643169689Skan	FPE_FLTDIV, /* 5E - DNML | DZ | OFL | UFL | STK */
644169689Skan	FPE_FLTSUB, /* 5F - INV | DNML | DZ | OFL | UFL | STK */
645169689Skan	FPE_FLTRES, /* 60 - IMP | STK */
646169689Skan	FPE_FLTSUB, /* 61 - INV | IMP | STK */
647169689Skan	FPE_FLTUND, /* 62 - DNML | IMP | STK */
648169689Skan	FPE_FLTSUB, /* 63 - INV | DNML | IMP | STK */
649169689Skan	FPE_FLTDIV, /* 64 - DZ | IMP | STK */
650169689Skan	FPE_FLTSUB, /* 65 - INV | DZ | IMP | STK */
651169689Skan	FPE_FLTDIV, /* 66 - DNML | DZ | IMP | STK */
652169689Skan	FPE_FLTSUB, /* 67 - INV | DNML | DZ | IMP | STK */
653169689Skan	FPE_FLTOVF, /* 68 - OFL | IMP | STK */
654169689Skan	FPE_FLTSUB, /* 69 - INV | OFL | IMP | STK */
655169689Skan	FPE_FLTUND, /* 6A - DNML | OFL | IMP | STK */
656169689Skan	FPE_FLTSUB, /* 6B - INV | DNML | OFL | IMP | STK */
657169689Skan	FPE_FLTDIV, /* 6C - DZ | OFL | IMP | STK */
658169689Skan	FPE_FLTSUB, /* 6D - INV | DZ | OFL | IMP | STK */
659169689Skan	FPE_FLTDIV, /* 6E - DNML | DZ | OFL | IMP | STK */
660169689Skan	FPE_FLTSUB, /* 6F - INV | DNML | DZ | OFL | IMP | STK */
661169689Skan	FPE_FLTUND, /* 70 - UFL | IMP | STK */
662169689Skan	FPE_FLTSUB, /* 71 - INV | UFL | IMP | STK */
663169689Skan	FPE_FLTUND, /* 72 - DNML | UFL | IMP | STK */
664169689Skan	FPE_FLTSUB, /* 73 - INV | DNML | UFL | IMP | STK */
665169689Skan	FPE_FLTDIV, /* 74 - DZ | UFL | IMP | STK */
666169689Skan	FPE_FLTSUB, /* 75 - INV | DZ | UFL | IMP | STK */
667169689Skan	FPE_FLTDIV, /* 76 - DNML | DZ | UFL | IMP | STK */
668169689Skan	FPE_FLTSUB, /* 77 - INV | DNML | DZ | UFL | IMP | STK */
669169689Skan	FPE_FLTOVF, /* 78 - OFL | UFL | IMP | STK */
670169689Skan	FPE_FLTSUB, /* 79 - INV | OFL | UFL | IMP | STK */
671169689Skan	FPE_FLTUND, /* 7A - DNML | OFL | UFL | IMP | STK */
672169689Skan	FPE_FLTSUB, /* 7B - INV | DNML | OFL | UFL | IMP | STK */
673169689Skan	FPE_FLTDIV, /* 7C - DZ | OFL | UFL | IMP | STK */
674169689Skan	FPE_FLTSUB, /* 7D - INV | DZ | OFL | UFL | IMP | STK */
675169689Skan	FPE_FLTDIV, /* 7E - DNML | DZ | OFL | UFL | IMP | STK */
676169689Skan	FPE_FLTSUB, /* 7F - INV | DNML | DZ | OFL | UFL | IMP | STK */
677169689Skan};
678169689Skan
679169689Skan#define ENCODE(_sw, _cw) (fpetable[(_sw & ~_cw & 0x3f) | (_sw & 0x40)])
680169689Skan
681169689Skan/*
682169689Skan * Preserve the FP status word, clear FP exceptions, then generate a SIGFPE.
683169689Skan *
684169689Skan * Clearing exceptions is necessary mainly to avoid IRQ13 bugs.  We now
685169689Skan * depend on longjmp() restoring a usable state.  Restoring the state
686169689Skan * or examining it might fail if we didn't clear exceptions.
687169689Skan *
688169689Skan * The error code chosen will be one of the FPE_... macros. It will be
689169689Skan * sent as the second argument to old BSD-style signal handlers and as
690169689Skan * "siginfo_t->si_code" (second argument) to SA_SIGINFO signal handlers.
691169689Skan *
692169689Skan * XXX the FP state is not preserved across signal handlers.  So signal
693169689Skan * handlers cannot afford to do FP unless they preserve the state or
694169689Skan * longjmp() out.  Both preserving the state and longjmp()ing may be
695169689Skan * destroyed by IRQ13 bugs.  Clearing FP exceptions is not an acceptable
696169689Skan * solution for signals other than SIGFPE.
697169689Skan */
698169689Skanvoid
699169689Skannpx_intr(dummy)
700169689Skan	void *dummy;
701169689Skan{
702169689Skan	int code;
703169689Skan	u_long cw;
704169689Skan	struct intrframe *frame;
705169689Skan
706169689Skan	if (npxproc == NULL || !npx_exists) {
707169689Skan		printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n",
708169689Skan		       npxproc, curproc, npx_exists);
709169689Skan		panic("npxintr from nowhere");
710169689Skan	}
711169689Skan	if (npxproc != curproc) {
712169689Skan		printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n",
713169689Skan		       npxproc, curproc, npx_exists);
714169689Skan		panic("npxintr from non-current process");
715169689Skan	}
716169689Skan
717169689Skan	outb(0xf0, 0);
718169689Skan	fnstsw(&curpcb->pcb_savefpu.sv_ex_sw);
719169689Skan	fnstcw(&cw);
720169689Skan	fnclex();
721169689Skan
722169689Skan	/*
723169689Skan	 * Pass exception to process.
724169689Skan	 */
725169689Skan	frame = (struct intrframe *)&dummy;	/* XXX */
726169689Skan	if ((ISPL(frame->if_cs) == SEL_UPL) || (frame->if_eflags & PSL_VM)) {
727169689Skan		/*
728169689Skan		 * Interrupt is essentially a trap, so we can afford to call
729169689Skan		 * the SIGFPE handler (if any) as soon as the interrupt
730169689Skan		 * returns.
731169689Skan		 *
732169689Skan		 * XXX little or nothing is gained from this, and plenty is
733169689Skan		 * lost - the interrupt frame has to contain the trap frame
734169689Skan		 * (this is otherwise only necessary for the rescheduling trap
735169689Skan		 * in doreti, and the frame for that could easily be set up
736169689Skan		 * just before it is used).
737169689Skan		 */
738169689Skan		curproc->p_md.md_regs = INTR_TO_TRAPFRAME(frame);
739169689Skan		/*
740169689Skan		 * Encode the appropriate code for detailed information on
741169689Skan		 * this exception.
742169689Skan		 */
743169689Skan		code = ENCODE(curpcb->pcb_savefpu.sv_ex_sw, cw);
744169689Skan		trapsignal(curproc, SIGFPE, code);
745169689Skan	} else {
746169689Skan		/*
747169689Skan		 * Nested interrupt.  These losers occur when:
748169689Skan		 *	o an IRQ13 is bogusly generated at a bogus time, e.g.:
749169689Skan		 *		o immediately after an fnsave or frstor of an
750169689Skan		 *		  error state.
751169689Skan		 *		o a couple of 386 instructions after
752169689Skan		 *		  "fstpl _memvar" causes a stack overflow.
753169689Skan		 *	  These are especially nasty when combined with a
754169689Skan		 *	  trace trap.
755169689Skan		 *	o an IRQ13 occurs at the same time as another higher-
756169689Skan		 *	  priority interrupt.
757169689Skan		 *
758169689Skan		 * Treat them like a true async interrupt.
759169689Skan		 */
760169689Skan		psignal(curproc, SIGFPE);
761169689Skan	}
762169689Skan}
763169689Skan
764169689Skan/*
765169689Skan * Implement device not available (DNA) exception
766169689Skan *
767169689Skan * It would be better to switch FP context here (if curproc != npxproc)
768169689Skan * and not necessarily for every context switch, but it is too hard to
769169689Skan * access foreign pcb's.
770169689Skan */
771169689Skanint
772169689Skannpxdna()
773169689Skan{
774169689Skan	if (!npx_exists)
775169689Skan		return (0);
776169689Skan	if (npxproc != NULL) {
777169689Skan		printf("npxdna: npxproc = %p, curproc = %p\n",
778169689Skan		       npxproc, curproc);
779169689Skan		panic("npxdna");
780169689Skan	}
781169689Skan	stop_emulating();
782169689Skan	/*
783169689Skan	 * Record new context early in case frstor causes an IRQ13.
784169689Skan	 */
785169689Skan	npxproc = curproc;
786169689Skan	curpcb->pcb_savefpu.sv_ex_sw = 0;
787169689Skan	/*
788169689Skan	 * The following frstor may cause an IRQ13 when the state being
789169689Skan	 * restored has a pending error.  The error will appear to have been
790169689Skan	 * triggered by the current (npx) user instruction even when that
791169689Skan	 * instruction is a no-wait instruction that should not trigger an
792169689Skan	 * error (e.g., fnclex).  On at least one 486 system all of the
793169689Skan	 * no-wait instructions are broken the same as frstor, so our
794169689Skan	 * treatment does not amplify the breakage.  On at least one
795169689Skan	 * 386/Cyrix 387 system, fnclex works correctly while frstor and
796169689Skan	 * fnsave are broken, so our treatment breaks fnclex if it is the
797169689Skan	 * first FPU instruction after a context switch.
798169689Skan	 */
799169689Skan	frstor(&curpcb->pcb_savefpu);
800169689Skan
801169689Skan	return (1);
802169689Skan}
803169689Skan
804169689Skan/*
805169689Skan * Wrapper for fnsave instruction to handle h/w bugs.  If there is an error
806169689Skan * pending, then fnsave generates a bogus IRQ13 on some systems.  Force
807169689Skan * any IRQ13 to be handled immediately, and then ignore it.  This routine is
808169689Skan * often called at splhigh so it must not use many system services.  In
809169689Skan * particular, it's much easier to install a special handler than to
810169689Skan * guarantee that it's safe to use npxintr() and its supporting code.
811169689Skan */
812169689Skanvoid
813169689Skannpxsave(addr)
814169689Skan	struct save87 *addr;
815169689Skan{
816169689Skan#ifdef SMP
817169689Skan
818169689Skan	stop_emulating();
819169689Skan	fnsave(addr);
820169689Skan	/* fnop(); */
821169689Skan	start_emulating();
822169689Skan	npxproc = NULL;
823169689Skan
824169689Skan#else /* SMP */
825169689Skan
826169689Skan	u_char	icu1_mask;
827169689Skan	u_char	icu2_mask;
828169689Skan	u_char	old_icu1_mask;
829169689Skan	u_char	old_icu2_mask;
830169689Skan	struct gate_descriptor	save_idt_npxintr;
831169689Skan
832169689Skan	disable_intr();
833169689Skan	old_icu1_mask = inb(IO_ICU1 + 1);
834169689Skan	old_icu2_mask = inb(IO_ICU2 + 1);
835169689Skan	save_idt_npxintr = idt[npx_intrno];
836169689Skan	outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask));
837169689Skan	outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0_imask >> 8));
838169689Skan	idt[npx_intrno] = npx_idt_probeintr;
839169689Skan	enable_intr();
840169689Skan	stop_emulating();
841169689Skan	fnsave(addr);
842169689Skan	fnop();
843169689Skan	start_emulating();
844169689Skan	npxproc = NULL;
845169689Skan	disable_intr();
846169689Skan	icu1_mask = inb(IO_ICU1 + 1);	/* masks may have changed */
847169689Skan	icu2_mask = inb(IO_ICU2 + 1);
848169689Skan	outb(IO_ICU1 + 1,
849169689Skan	     (icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask));
850169689Skan	outb(IO_ICU2 + 1,
851169689Skan	     (icu2_mask & ~(npx0_imask >> 8))
852169689Skan	     | (old_icu2_mask & (npx0_imask >> 8)));
853169689Skan	idt[npx_intrno] = save_idt_npxintr;
854169689Skan	enable_intr();		/* back to usual state */
855169689Skan
856169689Skan#endif /* SMP */
857169689Skan}
858169689Skan
859169689Skan#ifdef I586_CPU
860169689Skanstatic long
861169689Skantimezero(funcname, func)
862169689Skan	const char *funcname;
863169689Skan	void (*func) __P((void *buf, size_t len));
864169689Skan
865169689Skan{
866169689Skan	void *buf;
867169689Skan#define	BUFSIZE		1000000
868169689Skan	long usec;
869169689Skan	struct timeval finish, start;
870169689Skan
871169689Skan	buf = malloc(BUFSIZE, M_TEMP, M_NOWAIT);
872169689Skan	if (buf == NULL)
873169689Skan		return (BUFSIZE);
874169689Skan	microtime(&start);
875169689Skan	(*func)(buf, BUFSIZE);
876169689Skan	microtime(&finish);
877169689Skan	usec = 1000000 * (finish.tv_sec - start.tv_sec) +
878169689Skan	    finish.tv_usec - start.tv_usec;
879169689Skan	if (usec <= 0)
880169689Skan		usec = 1;
881169689Skan	if (bootverbose)
882169689Skan		printf("%s bandwidth = %ld bytes/sec\n",
883169689Skan		    funcname, (long)(BUFSIZE * (int64_t)1000000 / usec));
884169689Skan	free(buf, M_TEMP);
885169689Skan	return (usec);
886169689Skan}
887169689Skan#endif /* I586_CPU */
888169689Skan
889169689Skanstatic device_method_t npx_methods[] = {
890169689Skan	/* Device interface */
891169689Skan	DEVMETHOD(device_probe,		npx_probe),
892169689Skan	DEVMETHOD(device_attach,	npx_attach),
893169689Skan	DEVMETHOD(device_detach,	bus_generic_detach),
894169689Skan	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
895169689Skan	DEVMETHOD(device_suspend,	bus_generic_suspend),
896169689Skan	DEVMETHOD(device_resume,	bus_generic_resume),
897169689Skan
898169689Skan	{ 0, 0 }
899169689Skan};
900169689Skan
901169689Skanstatic driver_t npx_driver = {
902169689Skan	"npx",
903169689Skan	npx_methods,
904169689Skan	1,			/* no softc */
905169689Skan};
906169689Skan
907169689Skanstatic devclass_t npx_devclass;
908169689Skan
909169689Skan/*
910169689Skan * We prefer to attach to the root nexus so that the usual case (exception 16)
911169689Skan * doesn't describe the processor as being `on isa'.
912169689Skan */
913169689SkanDRIVER_MODULE(npx, nexus, npx_driver, npx_devclass, 0, 0);
914169689Skan
915169689Skan#endif /* NNPX > 0 */
916169689Skan