Deleted Added
full compact
fpu.c (122269) fpu.c (122292)
1/*-
2 * Copyright (c) 1990 William Jolitz.
3 * Copyright (c) 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 21 unchanged lines hidden (view full) ---

30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)npx.c 7.2 (Berkeley) 5/12/91
35 */
36
37#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1990 William Jolitz.
3 * Copyright (c) 1991 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:

--- 21 unchanged lines hidden (view full) ---

30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)npx.c 7.2 (Berkeley) 5/12/91
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/sys/amd64/amd64/fpu.c 122269 2003-11-08 00:13:43Z peter $");
38__FBSDID("$FreeBSD: head/sys/amd64/amd64/fpu.c 122292 2003-11-08 03:33:38Z peter $");
39
39
40#include "opt_debug_npx.h"
41#include "opt_isa.h"
42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/bus.h>
46#include <sys/kernel.h>
47#include <sys/lock.h>
48#include <sys/malloc.h>
49#include <sys/module.h>
50#include <sys/mutex.h>
51#include <sys/mutex.h>
52#include <sys/proc.h>
53#include <sys/sysctl.h>
54#include <machine/bus.h>
55#include <sys/rman.h>
40#include "opt_isa.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/bus.h>
45#include <sys/kernel.h>
46#include <sys/lock.h>
47#include <sys/malloc.h>
48#include <sys/module.h>
49#include <sys/mutex.h>
50#include <sys/mutex.h>
51#include <sys/proc.h>
52#include <sys/sysctl.h>
53#include <machine/bus.h>
54#include <sys/rman.h>
56#ifdef NPX_DEBUG
57#include <sys/syslog.h>
58#endif
59#include <sys/signalvar.h>
60#include <sys/user.h>
61
62#include <machine/cputypes.h>
63#include <machine/frame.h>
64#include <machine/md_var.h>
65#include <machine/pcb.h>
66#include <machine/psl.h>
67#include <machine/resource.h>
68#include <machine/specialreg.h>
69#include <machine/segments.h>
70#include <machine/ucontext.h>
71
72#include <amd64/isa/intr_machdep.h>
73#ifdef DEV_ISA
74#include <isa/isavar.h>
75#endif
76
77/*
55#include <sys/signalvar.h>
56#include <sys/user.h>
57
58#include <machine/cputypes.h>
59#include <machine/frame.h>
60#include <machine/md_var.h>
61#include <machine/pcb.h>
62#include <machine/psl.h>
63#include <machine/resource.h>
64#include <machine/specialreg.h>
65#include <machine/segments.h>
66#include <machine/ucontext.h>
67
68#include <amd64/isa/intr_machdep.h>
69#ifdef DEV_ISA
70#include <isa/isavar.h>
71#endif
72
73/*
78 * 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
74 * Floating point support.
79 */
80
81#if defined(__GNUC__) && !defined(lint)
82
83#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr)))
84#define fnclex() __asm("fnclex")
85#define fninit() __asm("fninit")
86#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr)))

--- 18 unchanged lines hidden (view full) ---

105
106#endif /* __GNUC__ */
107
108#define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save.sv_env.en_cw)
109#define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save.sv_env.en_sw)
110
111typedef u_char bool_t;
112
75 */
76
77#if defined(__GNUC__) && !defined(lint)
78
79#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr)))
80#define fnclex() __asm("fnclex")
81#define fninit() __asm("fninit")
82#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr)))

--- 18 unchanged lines hidden (view full) ---

101
102#endif /* __GNUC__ */
103
104#define GET_FPU_CW(thread) ((thread)->td_pcb->pcb_save.sv_env.en_cw)
105#define GET_FPU_SW(thread) ((thread)->td_pcb->pcb_save.sv_env.en_sw)
106
107typedef u_char bool_t;
108
113static int npx_attach(device_t dev);
114static void npx_identify(driver_t *driver, device_t parent);
115static int npx_probe(device_t dev);
109static int fpu_attach(device_t dev);
110static void fpu_identify(driver_t *driver, device_t parent);
111static int fpu_probe(device_t dev);
116
117int hw_float = 1;
118SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
119 CTLFLAG_RD, &hw_float, 0,
120 "Floatingpoint instructions executed in hardware");
121
112
113int hw_float = 1;
114SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
115 CTLFLAG_RD, &hw_float, 0,
116 "Floatingpoint instructions executed in hardware");
117
122static struct savefpu npx_cleanstate;
123static bool_t npx_cleanstate_ready;
118static struct savefpu fpu_cleanstate;
119static bool_t fpu_cleanstate_ready;
124
125/*
126 * Identify routine. Create a connection point on our parent for probing.
127 */
128static void
120
121/*
122 * Identify routine. Create a connection point on our parent for probing.
123 */
124static void
129npx_identify(driver, parent)
130 driver_t *driver;
131 device_t parent;
125fpu_identify(driver_t *driver, device_t parent)
132{
133 device_t child;
134
126{
127 device_t child;
128
135 child = BUS_ADD_CHILD(parent, 0, "npx", 0);
129 child = BUS_ADD_CHILD(parent, 0, "fpu", 0);
136 if (child == NULL)
130 if (child == NULL)
137 panic("npx_identify");
131 panic("fpu_identify");
138}
139
140/*
141 * Probe routine. Initialize cr0 to give correct behaviour for [f]wait
142 * whether the device exists or not (XXX should be elsewhere).
132}
133
134/*
135 * Probe routine. Initialize cr0 to give correct behaviour for [f]wait
136 * whether the device exists or not (XXX should be elsewhere).
143 * Modify device struct if npx doesn't need to use interrupts.
137 * Modify device struct if fpu doesn't need to use interrupts.
144 * Return 0 if device exists.
145 */
146static int
138 * Return 0 if device exists.
139 */
140static int
147npx_probe(dev)
148 device_t dev;
141fpu_probe(device_t dev)
149{
150
151 /*
142{
143
144 /*
152 * Partially reset the coprocessor, if any. Some BIOS's don't reset
153 * it after a warm boot.
154 */
155 outb(0xf1, 0); /* full reset on some systems, NOP on others */
156 outb(0xf0, 0); /* clear BUSY# latch */
157 /*
158 * Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
145 * Prepare to trap all ESC (i.e., FPU) instructions and all WAIT
159 * instructions. We must set the CR0_MP bit and use the CR0_TS
160 * bit to control the trap, because setting the CR0_EM bit does
161 * not cause WAIT instructions to trap. It's important to trap
162 * WAIT instructions - otherwise the "wait" variants of no-wait
163 * control instructions would degenerate to the "no-wait" variants
164 * after FP context switches but work correctly otherwise. It's
146 * instructions. We must set the CR0_MP bit and use the CR0_TS
147 * bit to control the trap, because setting the CR0_EM bit does
148 * not cause WAIT instructions to trap. It's important to trap
149 * WAIT instructions - otherwise the "wait" variants of no-wait
150 * control instructions would degenerate to the "no-wait" variants
151 * after FP context switches but work correctly otherwise. It's
165 * particularly important to trap WAITs when there is no NPX -
152 * particularly important to trap WAITs when there is no FPU -
166 * otherwise the "wait" variants would always degenerate.
167 *
168 * Try setting CR0_NE to get correct error reporting on 486DX's.
169 * Setting it should fail or do nothing on lesser processors.
170 */
171 load_cr0(rcr0() | CR0_MP | CR0_NE);
172 /*
173 * But don't trap while we're probing.
174 */
175 stop_emulating();
176 /*
177 * Finish resetting the coprocessor.
178 */
179 fninit();
180
181 device_set_desc(dev, "math processor");
153 * otherwise the "wait" variants would always degenerate.
154 *
155 * Try setting CR0_NE to get correct error reporting on 486DX's.
156 * Setting it should fail or do nothing on lesser processors.
157 */
158 load_cr0(rcr0() | CR0_MP | CR0_NE);
159 /*
160 * But don't trap while we're probing.
161 */
162 stop_emulating();
163 /*
164 * Finish resetting the coprocessor.
165 */
166 fninit();
167
168 device_set_desc(dev, "math processor");
169 device_quiet(dev);
182
183 return (0);
184}
185
186/*
187 * Attach routine - announce which it is, and wire into system
188 */
189static int
170
171 return (0);
172}
173
174/*
175 * Attach routine - announce which it is, and wire into system
176 */
177static int
190npx_attach(dev)
191 device_t dev;
178fpu_attach(device_t dev)
192{
193 register_t s;
194
179{
180 register_t s;
181
195 npxinit(__INITIAL_NPXCW__);
182 fpuinit(__INITIAL_FPUCW__);
196
183
197 if (npx_cleanstate_ready == 0) {
184 if (fpu_cleanstate_ready == 0) {
198 s = intr_disable();
199 stop_emulating();
185 s = intr_disable();
186 stop_emulating();
200 fxsave(&npx_cleanstate);
187 fxsave(&fpu_cleanstate);
201 start_emulating();
188 start_emulating();
202 npx_cleanstate_ready = 1;
189 fpu_cleanstate_ready = 1;
203 intr_restore(s);
204 }
205 return (0); /* XXX unused */
206}
207
208/*
209 * Initialize floating point unit.
210 */
211void
190 intr_restore(s);
191 }
192 return (0); /* XXX unused */
193}
194
195/*
196 * Initialize floating point unit.
197 */
198void
212npxinit(control)
213 u_short control;
199fpuinit(u_short control)
214{
215 static struct savefpu dummy;
216 register_t savecrit;
217
218 /*
219 * fninit has the same h/w bugs as fnsave. Use the detoxified
200{
201 static struct savefpu dummy;
202 register_t savecrit;
203
204 /*
205 * fninit has the same h/w bugs as fnsave. Use the detoxified
220 * fnsave to throw away any junk in the fpu. npxsave() initializes
206 * fnsave to throw away any junk in the fpu. fpusave() initializes
221 * the fpu and sets fpcurthread = NULL as important side effects.
222 */
223 savecrit = intr_disable();
207 * the fpu and sets fpcurthread = NULL as important side effects.
208 */
209 savecrit = intr_disable();
224 npxsave(&dummy);
210 fpusave(&dummy);
225 stop_emulating();
211 stop_emulating();
226 /* XXX npxsave() doesn't actually initialize the fpu in the SSE case. */
212 /* XXX fpusave() doesn't actually initialize the fpu in the SSE case. */
227 fninit();
228 fldcw(&control);
229 start_emulating();
230 intr_restore(savecrit);
231}
232
233/*
234 * Free coprocessor (if we have it).
235 */
236void
213 fninit();
214 fldcw(&control);
215 start_emulating();
216 intr_restore(savecrit);
217}
218
219/*
220 * Free coprocessor (if we have it).
221 */
222void
237npxexit(td)
238 struct thread *td;
223fpuexit(struct thread *td)
239{
224{
240#ifdef NPX_DEBUG
241 u_int masked_exceptions;
242#endif
243 register_t savecrit;
244
245 savecrit = intr_disable();
246 if (curthread == PCPU_GET(fpcurthread))
225 register_t savecrit;
226
227 savecrit = intr_disable();
228 if (curthread == PCPU_GET(fpcurthread))
247 npxsave(&PCPU_GET(curpcb)->pcb_save);
229 fpusave(&PCPU_GET(curpcb)->pcb_save);
248 intr_restore(savecrit);
230 intr_restore(savecrit);
249#ifdef NPX_DEBUG
250 masked_exceptions = GET_FPU_CW(td) & GET_FPU_SW(td) & 0x7f;
251 /*
252 * Log exceptions that would have trapped with the old
253 * control word (overflow, divide by 0, and invalid operand).
254 */
255 if (masked_exceptions & 0x0d)
256 log(LOG_ERR,
257"pid %d (%s) exited with masked floating point exceptions 0x%02x\n",
258 td->td_proc->p_pid, td->td_proc->p_comm,
259 masked_exceptions);
260#endif
261}
262
263int
231}
232
233int
264npxformat()
234fpuformat()
265{
266
267 return (_MC_FPFMT_XMM);
268}
269
270/*
271 * The following mechanism is used to ensure that the FPE_... value
272 * that is passed as a trapcode to the signal handler of the user

--- 178 unchanged lines hidden (view full) ---

451 *
452 * XXX the FP state is not preserved across signal handlers. So signal
453 * handlers cannot afford to do FP unless they preserve the state or
454 * longjmp() out. Both preserving the state and longjmp()ing may be
455 * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable
456 * solution for signals other than SIGFPE.
457 */
458int
235{
236
237 return (_MC_FPFMT_XMM);
238}
239
240/*
241 * The following mechanism is used to ensure that the FPE_... value
242 * that is passed as a trapcode to the signal handler of the user

--- 178 unchanged lines hidden (view full) ---

421 *
422 * XXX the FP state is not preserved across signal handlers. So signal
423 * handlers cannot afford to do FP unless they preserve the state or
424 * longjmp() out. Both preserving the state and longjmp()ing may be
425 * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable
426 * solution for signals other than SIGFPE.
427 */
428int
459npxtrap()
429fputrap()
460{
461 register_t savecrit;
462 u_short control, status;
463
464 savecrit = intr_disable();
465
466 /*
467 * Interrupt handling (for another interrupt) may have pushed the

--- 20 unchanged lines hidden (view full) ---

488 * It would be better to switch FP context here (if curthread != fpcurthread)
489 * and not necessarily for every context switch, but it is too hard to
490 * access foreign pcb's.
491 */
492
493static int err_count = 0;
494
495int
430{
431 register_t savecrit;
432 u_short control, status;
433
434 savecrit = intr_disable();
435
436 /*
437 * Interrupt handling (for another interrupt) may have pushed the

--- 20 unchanged lines hidden (view full) ---

458 * It would be better to switch FP context here (if curthread != fpcurthread)
459 * and not necessarily for every context switch, but it is too hard to
460 * access foreign pcb's.
461 */
462
463static int err_count = 0;
464
465int
496npxdna()
466fpudna()
497{
498 struct pcb *pcb;
499 register_t s;
500 u_short control;
501
502 if (PCPU_GET(fpcurthread) == curthread) {
467{
468 struct pcb *pcb;
469 register_t s;
470 u_short control;
471
472 if (PCPU_GET(fpcurthread) == curthread) {
503 printf("npxdna: fpcurthread == curthread %d times\n",
473 printf("fpudna: fpcurthread == curthread %d times\n",
504 ++err_count);
505 stop_emulating();
506 return (1);
507 }
508 if (PCPU_GET(fpcurthread) != NULL) {
474 ++err_count);
475 stop_emulating();
476 return (1);
477 }
478 if (PCPU_GET(fpcurthread) != NULL) {
509 printf("npxdna: fpcurthread = %p (%d), curthread = %p (%d)\n",
479 printf("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n",
510 PCPU_GET(fpcurthread),
511 PCPU_GET(fpcurthread)->td_proc->p_pid,
512 curthread, curthread->td_proc->p_pid);
480 PCPU_GET(fpcurthread),
481 PCPU_GET(fpcurthread)->td_proc->p_pid,
482 curthread, curthread->td_proc->p_pid);
513 panic("npxdna");
483 panic("fpudna");
514 }
515 s = intr_disable();
516 stop_emulating();
517 /*
484 }
485 s = intr_disable();
486 stop_emulating();
487 /*
518 * Record new context early in case frstor causes an IRQ13.
488 * Record new context early in case frstor causes a trap.
519 */
520 PCPU_SET(fpcurthread, curthread);
521 pcb = PCPU_GET(curpcb);
522
489 */
490 PCPU_SET(fpcurthread, curthread);
491 pcb = PCPU_GET(curpcb);
492
523 if ((pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
493 if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) {
524 /*
525 * This is the first time this thread has used the FPU or
526 * the PCB doesn't contain a clean FPU state. Explicitly
527 * initialize the FPU and load the default control word.
528 */
529 fninit();
494 /*
495 * This is the first time this thread has used the FPU or
496 * the PCB doesn't contain a clean FPU state. Explicitly
497 * initialize the FPU and load the default control word.
498 */
499 fninit();
530 control = __INITIAL_NPXCW__;
500 control = __INITIAL_FPUCW__;
531 fldcw(&control);
501 fldcw(&control);
532 pcb->pcb_flags |= PCB_NPXINITDONE;
502 pcb->pcb_flags |= PCB_FPUINITDONE;
533 } else {
534 /*
535 * The following frstor may cause a trap when the state
536 * being restored has a pending error. The error will
503 } else {
504 /*
505 * The following frstor may cause a trap when the state
506 * being restored has a pending error. The error will
537 * appear to have been triggered by the current (npx) user
507 * appear to have been triggered by the current (fpu) user
538 * instruction even when that instruction is a no-wait
539 * instruction that should not trigger an error (e.g.,
540 * instructions are broken the same as frstor, so our
541 * treatment does not amplify the breakage.
542 */
543 fxrstor(&pcb->pcb_save);
544 }
545 intr_restore(s);
546
547 return (1);
548}
549
550/*
508 * instruction even when that instruction is a no-wait
509 * instruction that should not trigger an error (e.g.,
510 * instructions are broken the same as frstor, so our
511 * treatment does not amplify the breakage.
512 */
513 fxrstor(&pcb->pcb_save);
514 }
515 intr_restore(s);
516
517 return (1);
518}
519
520/*
551 * Wrapper for fnsave instruction, partly to handle hardware bugs. When npx
552 * exceptions are reported via IRQ13, spurious IRQ13's may be triggered by
553 * no-wait npx instructions. See the Intel application note AP-578 for
554 * details. This doesn't cause any additional complications here. IRQ13's
555 * are inherently asynchronous unless the CPU is frozen to deliver them --
556 * one that started in userland may be delivered many instructions later,
557 * after the process has entered the kernel. It may even be delivered after
558 * the fnsave here completes. A spurious IRQ13 for the fnsave is handled in
559 * the same way as a very-late-arriving non-spurious IRQ13 from user mode:
560 * it is normally ignored at first because we set fpcurthread to NULL; it is
561 * normally retriggered in npxdna() after return to user mode.
521 * Wrapper for fnsave instruction.
562 *
522 *
563 * npxsave() must be called with interrupts disabled, so that it clears
523 * fpusave() must be called with interrupts disabled, so that it clears
564 * fpcurthread atomically with saving the state. We require callers to do the
565 * disabling, since most callers need to disable interrupts anyway to call
524 * fpcurthread atomically with saving the state. We require callers to do the
525 * disabling, since most callers need to disable interrupts anyway to call
566 * npxsave() atomically with checking fpcurthread.
567 *
568 * A previous version of npxsave() went to great lengths to excecute fnsave
569 * with interrupts enabled in case executing it froze the CPU. This case
570 * can't happen, at least for Intel CPU/NPX's. Spurious IRQ13's don't imply
571 * spurious freezes.
526 * fpusave() atomically with checking fpcurthread.
572 */
573void
527 */
528void
574npxsave(addr)
575 struct savefpu *addr;
529fpusave(struct savefpu *addr)
576{
577
578 stop_emulating();
579 fxsave(addr);
530{
531
532 stop_emulating();
533 fxsave(addr);
580
581 start_emulating();
582 PCPU_SET(fpcurthread, NULL);
583}
584
585/*
586 * This should be called with interrupts disabled and only when the owning
587 * FPU thread is non-null.
588 */
589void
534 start_emulating();
535 PCPU_SET(fpcurthread, NULL);
536}
537
538/*
539 * This should be called with interrupts disabled and only when the owning
540 * FPU thread is non-null.
541 */
542void
590npxdrop()
543fpudrop()
591{
592 struct thread *td;
593
594 td = PCPU_GET(fpcurthread);
595 PCPU_SET(fpcurthread, NULL);
544{
545 struct thread *td;
546
547 td = PCPU_GET(fpcurthread);
548 PCPU_SET(fpcurthread, NULL);
596 td->td_pcb->pcb_flags &= ~PCB_NPXINITDONE;
549 td->td_pcb->pcb_flags &= ~PCB_FPUINITDONE;
597 start_emulating();
598}
599
600/*
601 * Get the state of the FPU without dropping ownership (if possible).
602 * It returns the FPU ownership status.
603 */
604int
550 start_emulating();
551}
552
553/*
554 * Get the state of the FPU without dropping ownership (if possible).
555 * It returns the FPU ownership status.
556 */
557int
605npxgetregs(td, addr)
606 struct thread *td;
607 struct savefpu *addr;
558fpugetregs(struct thread *td, struct savefpu *addr)
608{
609 register_t s;
610
559{
560 register_t s;
561
611 if ((td->td_pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
612 if (npx_cleanstate_ready)
613 bcopy(&npx_cleanstate, addr, sizeof(npx_cleanstate));
562 if ((td->td_pcb->pcb_flags & PCB_FPUINITDONE) == 0) {
563 if (fpu_cleanstate_ready)
564 bcopy(&fpu_cleanstate, addr, sizeof(fpu_cleanstate));
614 else
615 bzero(addr, sizeof(*addr));
616 return (_MC_FPOWNED_NONE);
617 }
618 s = intr_disable();
619 if (td == PCPU_GET(fpcurthread)) {
620 fxsave(addr);
621 intr_restore(s);

--- 4 unchanged lines hidden (view full) ---

626 return (_MC_FPOWNED_PCB);
627 }
628}
629
630/*
631 * Set the state of the FPU.
632 */
633void
565 else
566 bzero(addr, sizeof(*addr));
567 return (_MC_FPOWNED_NONE);
568 }
569 s = intr_disable();
570 if (td == PCPU_GET(fpcurthread)) {
571 fxsave(addr);
572 intr_restore(s);

--- 4 unchanged lines hidden (view full) ---

577 return (_MC_FPOWNED_PCB);
578 }
579}
580
581/*
582 * Set the state of the FPU.
583 */
584void
634npxsetregs(td, addr)
635 struct thread *td;
636 struct savefpu *addr;
585fpusetregs(struct thread *td, struct savefpu *addr)
637{
638 register_t s;
639
640 s = intr_disable();
641 if (td == PCPU_GET(fpcurthread)) {
642 fxrstor(addr);
643 intr_restore(s);
644 } else {
645 intr_restore(s);
646 bcopy(addr, &td->td_pcb->pcb_save, sizeof(*addr));
647 }
586{
587 register_t s;
588
589 s = intr_disable();
590 if (td == PCPU_GET(fpcurthread)) {
591 fxrstor(addr);
592 intr_restore(s);
593 } else {
594 intr_restore(s);
595 bcopy(addr, &td->td_pcb->pcb_save, sizeof(*addr));
596 }
648 curthread->td_pcb->pcb_flags |= PCB_NPXINITDONE;
597 curthread->td_pcb->pcb_flags |= PCB_FPUINITDONE;
649}
650
598}
599
651static device_method_t npx_methods[] = {
600static device_method_t fpu_methods[] = {
652 /* Device interface */
601 /* Device interface */
653 DEVMETHOD(device_identify, npx_identify),
654 DEVMETHOD(device_probe, npx_probe),
655 DEVMETHOD(device_attach, npx_attach),
602 DEVMETHOD(device_identify, fpu_identify),
603 DEVMETHOD(device_probe, fpu_probe),
604 DEVMETHOD(device_attach, fpu_attach),
656 DEVMETHOD(device_detach, bus_generic_detach),
657 DEVMETHOD(device_shutdown, bus_generic_shutdown),
658 DEVMETHOD(device_suspend, bus_generic_suspend),
659 DEVMETHOD(device_resume, bus_generic_resume),
660
661 { 0, 0 }
662};
663
605 DEVMETHOD(device_detach, bus_generic_detach),
606 DEVMETHOD(device_shutdown, bus_generic_shutdown),
607 DEVMETHOD(device_suspend, bus_generic_suspend),
608 DEVMETHOD(device_resume, bus_generic_resume),
609
610 { 0, 0 }
611};
612
664static driver_t npx_driver = {
665 "npx",
666 npx_methods,
613static driver_t fpu_driver = {
614 "fpu",
615 fpu_methods,
667 1, /* no softc */
668};
669
616 1, /* no softc */
617};
618
670static devclass_t npx_devclass;
619static devclass_t fpu_devclass;
671
672/*
673 * We prefer to attach to the root nexus so that the usual case (exception 16)
674 * doesn't describe the processor as being `on isa'.
675 */
620
621/*
622 * We prefer to attach to the root nexus so that the usual case (exception 16)
623 * doesn't describe the processor as being `on isa'.
624 */
676DRIVER_MODULE(npx, nexus, npx_driver, npx_devclass, 0, 0);
625DRIVER_MODULE(fpu, nexus, fpu_driver, fpu_devclass, 0, 0);
677
678#ifdef DEV_ISA
679/*
680 * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI.
681 */
626
627#ifdef DEV_ISA
628/*
629 * This sucks up the legacy ISA support assignments from PNPBIOS/ACPI.
630 */
682static struct isa_pnp_id npxisa_ids[] = {
631static struct isa_pnp_id fpuisa_ids[] = {
683 { 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */
684 { 0 }
685};
686
687static int
632 { 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */
633 { 0 }
634};
635
636static int
688npxisa_probe(device_t dev)
637fpuisa_probe(device_t dev)
689{
690 int result;
638{
639 int result;
691 if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, npxisa_ids)) <= 0) {
640
641 result = ISA_PNP_PROBE(device_get_parent(dev), dev, fpuisa_ids);
642 if (result <= 0)
692 device_quiet(dev);
643 device_quiet(dev);
693 }
694 return(result);
644 return (result);
695}
696
697static int
645}
646
647static int
698npxisa_attach(device_t dev)
648fpuisa_attach(device_t dev)
699{
649{
650
700 return (0);
701}
702
651 return (0);
652}
653
703static device_method_t npxisa_methods[] = {
654static device_method_t fpuisa_methods[] = {
704 /* Device interface */
655 /* Device interface */
705 DEVMETHOD(device_probe, npxisa_probe),
706 DEVMETHOD(device_attach, npxisa_attach),
656 DEVMETHOD(device_probe, fpuisa_probe),
657 DEVMETHOD(device_attach, fpuisa_attach),
707 DEVMETHOD(device_detach, bus_generic_detach),
708 DEVMETHOD(device_shutdown, bus_generic_shutdown),
709 DEVMETHOD(device_suspend, bus_generic_suspend),
710 DEVMETHOD(device_resume, bus_generic_resume),
711
712 { 0, 0 }
713};
714
658 DEVMETHOD(device_detach, bus_generic_detach),
659 DEVMETHOD(device_shutdown, bus_generic_shutdown),
660 DEVMETHOD(device_suspend, bus_generic_suspend),
661 DEVMETHOD(device_resume, bus_generic_resume),
662
663 { 0, 0 }
664};
665
715static driver_t npxisa_driver = {
716 "npxisa",
717 npxisa_methods,
666static driver_t fpuisa_driver = {
667 "fpuisa",
668 fpuisa_methods,
718 1, /* no softc */
719};
720
669 1, /* no softc */
670};
671
721static devclass_t npxisa_devclass;
672static devclass_t fpuisa_devclass;
722
673
723DRIVER_MODULE(npxisa, isa, npxisa_driver, npxisa_devclass, 0, 0);
724DRIVER_MODULE(npxisa, acpi, npxisa_driver, npxisa_devclass, 0, 0);
674DRIVER_MODULE(fpuisa, isa, fpuisa_driver, fpuisa_devclass, 0, 0);
675DRIVER_MODULE(fpuisa, acpi, fpuisa_driver, fpuisa_devclass, 0, 0);
725#endif /* DEV_ISA */
676#endif /* DEV_ISA */