xref: /freebsd/sys/dev/pci/pci.c (revision 17ee9d00bc1ae1e598c38f25826f861e4bc6c3ce)
1 /**************************************************************************
2 **
3 **  $Id: pci.c,v 1.9 1994/11/02 23:47:13 se Exp $
4 **
5 **  General subroutines for the PCI bus on 80*86 systems.
6 **  pci_configure ()
7 **
8 **  386bsd / FreeBSD
9 **
10 **-------------------------------------------------------------------------
11 **
12 ** Copyright (c) 1994 Wolfgang Stanglmeier.  All rights reserved.
13 **
14 ** Redistribution and use in source and binary forms, with or without
15 ** modification, are permitted provided that the following conditions
16 ** are met:
17 ** 1. Redistributions of source code must retain the above copyright
18 **    notice, this list of conditions and the following disclaimer.
19 ** 2. Redistributions in binary form must reproduce the above copyright
20 **    notice, this list of conditions and the following disclaimer in the
21 **    documentation and/or other materials provided with the distribution.
22 ** 3. The name of the author may not be used to endorse or promote products
23 **    derived from this software without specific prior written permission.
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 **
36 ***************************************************************************
37 */
38 
39 #include <pci.h>
40 #if NPCI > 0
41 
42 #ifndef __FreeBSD2__
43 #if __FreeBSD__ >= 2
44 #define	__FreeBSD2__
45 #endif
46 #endif
47 
48 /*========================================================
49 **
50 **	#includes  and  declarations
51 **
52 **========================================================
53 */
54 
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/malloc.h>
58 #include <sys/errno.h>
59 #include <sys/kernel.h>
60 
61 #include <vm/vm.h>
62 #include <vm/vm_param.h>
63 
64 #include <pci/pcivar.h>
65 #include <pci/pcireg.h>
66 #include <pci/pcibus.h>
67 
68 #include <machine/pmap.h>
69 #ifdef __FreeBSD2__
70 #include <sys/devconf.h>
71 
72 struct pci_devconf {
73 	struct kern_devconf pdc_kdc;
74 	struct pci_info     pdc_pi;
75 };
76 
77 static int
78 pci_externalize (struct proc *, struct kern_devconf *, void *, size_t);
79 
80 static int
81 pci_internalize (struct proc *, struct kern_devconf *, void *, size_t);
82 #else /* __FreeBSD2__ */
83 
84 /*
85 **	Function prototypes missing in system headers
86 */
87 
88 extern	pmap_t pmap_kernel(void);
89 static	vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize);
90 #endif /* __FreeBSD2__ */
91 
92 
93 /*========================================================
94 **
95 **	Autoconfiguration of pci devices.
96 **
97 **	This is reverse to the isa configuration.
98 **	(1) find a pci device.
99 **	(2) look for a driver.
100 **
101 **========================================================
102 */
103 
104 /*--------------------------------------------------------
105 **
106 **	The pci devices can be mapped to any address.
107 **	As default we start at the last gigabyte.
108 **
109 **--------------------------------------------------------
110 */
111 
112 #ifndef PCI_PMEM_START
113 #define PCI_PMEM_START 0xc0000000
114 #endif
115 
116 static	vm_offset_t pci_paddr = PCI_PMEM_START;
117 
118 /*--------------------------------------------------------
119 **
120 **	The pci ports can be mapped to any address.
121 **	As default we start at 0x400
122 **
123 **--------------------------------------------------------
124 */
125 
126 #ifndef PCI_PORT_START
127 #define PCI_PORT_START 0xbc00
128 #endif
129 
130 static	u_short pci_ioaddr = PCI_PORT_START;
131 
132 /*--------------------------------------------------------
133 **
134 **	The pci device interrupt lines should have been
135 **	assigned by the bios. But if the bios failed to
136 **	to it, we set it.
137 **
138 **--------------------------------------------------------
139 */
140 
141 #ifndef PCI_IRQ
142 #define PCI_IRQ 0
143 #endif
144 
145 static	u_long      pci_irq   = PCI_IRQ;
146 
147 /*---------------------------------------------------------
148 **
149 **	pci_configure ()
150 **
151 **	Probe all devices on pci bus and attach them.
152 **
153 **	May be called more than once.
154 **	Any device is attached only once.
155 **	(Attached devices are remembered in pci_seen.)
156 **
157 **---------------------------------------------------------
158 */
159 
160 static void not_supported (pcici_t tag, u_long type);
161 
162 static unsigned long pci_seen[NPCI];
163 
164 static int pci_conf_count;
165 
166 void pci_configure()
167 {
168 	u_char	device,last_device;
169 	u_short	bus;
170 	pcici_t	tag;
171 	pcidi_t type;
172 	u_long	data;
173 	int	unit;
174 	int	pci_mechanism;
175 	int	pciint;
176 	int	irq;
177 	char*	name=0;
178 	vm_offset_t old_addr=pci_paddr;
179 	u_short	old_ioaddr=pci_ioaddr;
180 
181 	int	dvi;
182 	struct pci_device *dvp=0;
183 
184 #ifdef __FreeBSD2__
185 	struct pci_devconf *pdcp;
186 #endif
187 
188 	/*
189 	**	first check pci bus driver available
190 	*/
191 
192 	if (pcibus_set.ls_length <= 0)
193 		return;
194 
195 #define pcibus (*((struct pcibus*) pcibus_set.ls_items[0]))
196 	/*
197 	**	check pci bus present
198 	*/
199 
200 	pci_mechanism = pcibus.pb_mode ();
201 	if (!pci_mechanism) return;
202 	last_device = pci_mechanism==1 ? 31 : 15;
203 
204 	/*
205 	**	hello world ..
206 	*/
207 
208 
209 	for (bus=0;bus<NPCI;bus++) {
210 #ifndef PCI_QUIET
211 	    printf ("%s%d: scanning device 0..%d, mechanism=%d.\n",
212 		pcibus.pb_name, bus, last_device, pci_mechanism);
213 #endif
214 	    for (device=0; device<=last_device; device ++) {
215 
216 		if (pci_seen[bus] & (1ul << device))
217 			continue;
218 
219 		tag  = pcibus.pb_tag (bus, device, 0);
220 		type = pcibus.pb_read (tag, PCI_ID_REG);
221 
222 		if ((!type) || (type==0xfffffffful)) continue;
223 
224 		/*
225 		**	lookup device in ioconfiguration:
226 		*/
227 
228         	for (dvi=0; dvi<pcidevice_set.ls_length; dvi++) {
229 			dvp = (struct pci_device*) pcidevice_set.ls_items[dvi];
230 			if ((name=(*dvp->pd_probe)(tag, type)))
231 				break;
232 			dvp = NULL;
233 		};
234 
235 		if (dvp==NULL) {
236 #ifndef PCI_QUIET
237 			if (pci_conf_count)
238 				continue;
239 			printf("%s%d:%d: ", pcibus.pb_name, bus, device);
240 			not_supported (tag, type);
241 #endif
242 			continue;
243 		};
244 
245 		pci_seen[bus] |= (1ul << device);
246 		/*
247 		**	Get and increment the unit.
248 		*/
249 
250 		unit = (*dvp->pd_count)++;
251 
252 		/*
253 		**	ignore device ?
254 		*/
255 
256 		if (!*name) continue;
257 
258 		/*
259 		**	Announce this device
260 		*/
261 
262 		printf ("%s%d <%s>", dvp->pd_name, unit, name);
263 
264 		/*
265 		**	Get the int pin number (pci interrupt number a-d)
266 		**	from the pci configuration space.
267 		*/
268 
269 		data = pcibus.pb_read (tag, PCI_INTERRUPT_REG);
270 		pciint = PCI_INTERRUPT_PIN_EXTRACT(data);
271 
272 		if (pciint) {
273 
274 			printf (" int %c", 0x60+pciint);
275 
276 			/*
277 			**	If the interrupt line register is not set,
278 			**	set it now from PCI_IRQ.
279 			*/
280 
281 			if (!(PCI_INTERRUPT_LINE_EXTRACT(data))) {
282 
283 				irq = pci_irq & 0x0f;
284 				pci_irq >>= 4;
285 
286 				data = PCI_INTERRUPT_LINE_INSERT(data, irq);
287 				printf (" (config)");
288 				pcibus.pb_write (tag, PCI_INTERRUPT_REG, data);
289 			};
290 
291 			irq = PCI_INTERRUPT_LINE_EXTRACT(data);
292 
293 			/*
294 			**	If it's zero, the isa irq number is unknown,
295 			**	and we cannot bind the pci interrupt to isa.
296 			*/
297 
298 			if (irq)
299 				printf (" irq %d", irq);
300 			else
301 				printf (" not bound");
302 		};
303 
304 		/*
305 		**	enable memory access
306 		*/
307 
308 		data = (pcibus.pb_read (tag, PCI_COMMAND_STATUS_REG)
309 			& 0xffff) | PCI_COMMAND_MEM_ENABLE;
310 
311 		pcibus.pb_write (tag, (u_char) PCI_COMMAND_STATUS_REG, data);
312 
313 		/*
314 		**	show pci slot.
315 		*/
316 
317 		printf (" on pci%d:%d\n", bus, device);
318 
319 #ifdef __FreeBSD2__
320 
321 		/*
322 		**	Allocate a devconf structure
323 		*/
324 
325 		pdcp = (struct pci_devconf *)
326 			malloc (sizeof (struct pci_devconf),M_DEVBUF,M_WAITOK);
327 
328 		/*
329 		**	Fill in.
330 		**
331 		**	Sorry, this is not yet complete.
332 		**	We should, and eventually will, set the
333 		**	parent pointer to a pci bus devconf structure,
334 		**	and arrange to set the state field dynamically.
335 		**
336 		**	But I'll go to vacation today, and after all,
337 		**	wasn't there a new feature freeze on Oct 1.?
338 		*/
339 
340 		pdcp -> pdc_pi.pi_bus	 = bus;
341 		pdcp -> pdc_pi.pi_device = device;
342 
343 		pdcp -> pdc_kdc.kdc_name = dvp->pd_name;
344 		pdcp -> pdc_kdc.kdc_unit = unit;
345 
346 		pdcp -> pdc_kdc.kdc_md.mddc_devtype = MDDT_PCI;
347 
348 		pdcp -> pdc_kdc.kdc_externalize = pci_externalize;
349 		pdcp -> pdc_kdc.kdc_internalize = pci_internalize;
350 
351 		pdcp -> pdc_kdc.kdc_datalen     = PCI_EXTERNAL_LEN;
352 		pdcp -> pdc_kdc.kdc_parentdata  = &pdcp->pdc_pi;
353 		pdcp -> pdc_kdc.kdc_state       = DC_UNKNOWN;
354 		pdcp -> pdc_kdc.kdc_description = name;
355 
356 		/*
357 		**	And register this device
358 		*/
359 
360 		dev_attach (&pdcp->pdc_kdc);
361 
362 #endif /* __FreeBSD2__ */
363 
364 
365 		/*
366 		**	attach device
367 		**	may produce additional log messages,
368 		**	i.e. when installing subdevices.
369 		*/
370 
371 		(*dvp->pd_attach) (tag, unit);
372 	    };
373 	};
374 
375 #ifndef PCI_QUIET
376 	if (pci_paddr != old_addr)
377 		printf ("pci uses physical addresses from 0x%lx to 0x%lx\n",
378 			(u_long)PCI_PMEM_START, (u_long)pci_paddr);
379 	if (pci_ioaddr != old_ioaddr)
380 		printf ("pci devices use ioports from 0x%x to 0x%x\n",
381 			(unsigned)PCI_PORT_START, (unsigned)pci_ioaddr);
382 #endif
383 	pci_conf_count++;
384 }
385 
386 /*-----------------------------------------------------------------
387 **
388 **	The following functions are provided for the device driver
389 **	to read/write the configuration space.
390 **
391 **	pci_conf_read():
392 **		Read a long word from the pci configuration space.
393 **		Requires a tag (from pcitag) and the register
394 **		number (should be a long word alligned one).
395 **
396 **	pci_conf_write():
397 **		Writes a long word to the pci configuration space.
398 **		Requires a tag (from pcitag), the register number
399 **		(should be a long word alligned one), and a value.
400 **
401 **-----------------------------------------------------------------
402 */
403 
404 u_long
405 pci_conf_read  (pcici_t tag, u_long reg)
406 {
407 	return (pcibus.pb_read (tag, reg));
408 }
409 
410 void
411 pci_conf_write (pcici_t tag, u_long reg, u_long data)
412 {
413 	pcibus.pb_write (tag, reg, data);
414 }
415 
416 /*-----------------------------------------------------------------------
417 **
418 **	Map device into port space.
419 **
420 **	PCI-Specification:  6.2.5.1: address maps
421 **
422 **-----------------------------------------------------------------------
423 */
424 
425 int pci_map_port (pcici_t tag, u_long reg, u_short* pa)
426 {
427 	u_long	data;
428 	u_short	size;
429 
430 	/*
431 	**	sanity check
432 	*/
433 
434 	if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) {
435 		printf ("pci_map_port failed: bad register=0x%x\n",
436 	       		(unsigned)reg);
437 		return (0);
438 	};
439 
440 	/*
441 	**	get size and type of port
442 	**
443 	**	type is in the lowest two bits.
444 	**	If device requires 2^n bytes, the next
445 	**	n-2 bits are hardwired as 0.
446 	*/
447 
448 	pcibus.pb_write (tag, reg, 0xfffffffful);
449 	data = pcibus.pb_read (tag, reg);
450 
451 	switch (data & 0x03) {
452 
453 	case PCI_MAP_IO:
454 		break;
455 
456 	default:	/* unknown */
457 		printf ("pci_map_port failed: bad port type=0x%x\n",
458 	       		(unsigned) data);
459 		return (0);
460 	};
461 
462 	/*
463 	**	get the size
464 	*/
465 
466 	size = -(data &  PCI_MAP_IO_ADDRESS_MASK);
467 
468 	if (!size) return (0);
469 
470 	/*
471 	**	align physical address to virtual size
472 	*/
473 
474 	if ((data = pci_ioaddr % size))
475 		pci_ioaddr += size - data;
476 
477 #ifndef PCI_QUIET
478 	/*
479 	**	display values.
480 	*/
481 
482 	printf ("\treg%d: ioaddr=0x%x size=0x%x\n",
483 		(unsigned) reg, (unsigned) pci_ioaddr, (unsigned) size);
484 #endif
485 
486 	/*
487 	**	set device address
488 	*/
489 
490 	pcibus.pb_write (tag, reg, (u_long) pci_ioaddr);
491 
492 	/*
493 	**	return them to the driver
494 	*/
495 
496 	*pa = pci_ioaddr;
497 
498 	/*
499 	**	and don't forget to increment pci_ioaddr
500 	*/
501 
502 	pci_ioaddr += size;
503 
504 	return (1);
505 }
506 
507 /*-----------------------------------------------------------------------
508 **
509 **	Map device into virtual and physical space
510 **
511 **	PCI-Specification:  6.2.5.1: address maps
512 **
513 **-----------------------------------------------------------------------
514 */
515 
516 int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa)
517 {
518 	u_long data;
519 	vm_size_t vsize;
520 	vm_offset_t vaddr;
521 	int i;
522 
523 	/*
524 	**	sanity check
525 	*/
526 
527 	if (reg < PCI_MAP_REG_START || reg >= PCI_MAP_REG_END || (reg & 3)) {
528 		printf ("pci_map_mem failed: bad register=0x%x\n",
529 	       		(unsigned)reg);
530 		return (0);
531 	};
532 
533 	/*
534 	**	get size and type of memory
535 	**
536 	**	type is in the lowest four bits.
537 	**	If device requires 2^n bytes, the next
538 	**	n-4 bits are read as 0.
539 	*/
540 
541 	pcibus.pb_write (tag, reg, 0xfffffffful);
542 	data = pcibus.pb_read (tag, reg);
543 
544 	switch (data & 0x0f) {
545 
546 	case PCI_MAP_MEMORY_TYPE_32BIT:	/* 32 bit non cachable */
547 		break;
548 
549 	default:	/* unknown */
550 		printf ("pci_map_mem failed: bad memory type=0x%x\n",
551 	       		(unsigned) data);
552 		return (0);
553 	};
554 
555 	/*
556 	**	mask out the type,
557 	**	and round up to a page size
558 	*/
559 
560 	vsize = round_page (-(data &  PCI_MAP_MEMORY_ADDRESS_MASK));
561 
562 	if (!vsize) return (0);
563 
564 	/*
565 	**	align physical address to virtual size
566 	*/
567 
568 	if ((data = pci_paddr % vsize))
569 		pci_paddr += vsize - data;
570 
571 	vaddr = (vm_offset_t) pmap_mapdev (pci_paddr, vsize);
572 
573 
574 	if (!vaddr) return (0);
575 
576 #ifndef PCI_QUIET
577 	/*
578 	**	display values.
579 	*/
580 
581 	printf ("\treg%d: virtual=0x%lx physical=0x%lx\n",
582 		(unsigned) reg, (u_long)vaddr, (u_long)pci_paddr);
583 #endif
584 
585 	/*
586 	**	probe for already mapped device.
587 	*/
588 
589 	for (i=0; i<vsize; i+=4) {
590 		u_long* addr = (u_long*) (vaddr+i);
591 		data = *addr;
592 		if (data != 0xffffffff) {
593 			printf ("WARNING: possible address conflict "
594 				"at 0x%08x (read: 0x%08x).\n",
595 				(unsigned) pci_paddr+i, (unsigned) data);
596 			break;
597 		};
598 	};
599 
600 	/*
601 	**	return them to the driver
602 	*/
603 
604 	*va = vaddr;
605 	*pa = pci_paddr;
606 
607 	/*
608 	**	set device address
609 	*/
610 
611 	pcibus.pb_write (tag, reg, pci_paddr);
612 
613 	/*
614 	**	and don't forget to increment pci_paddr
615 	*/
616 
617 	pci_paddr += vsize;
618 
619 	return (1);
620 }
621 
622 /*------------------------------------------------------------
623 **
624 **	Interface functions for the devconf module.
625 **
626 **------------------------------------------------------------
627 */
628 
629 static int
630 pci_externalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t l)
631 {
632 	struct pci_externalize_buffer buffer;
633 	struct pci_info * pip = kdcp->kdc_parentdata;
634 	pcici_t tag;
635 	int	i;
636 
637 	if (l < sizeof buffer) {
638 		return ENOMEM;
639 	};
640 
641 	tag = pcibus.pb_tag (pip->pi_bus, pip->pi_device, 0);
642 
643 	buffer.peb_pci_info	= *pip;
644 
645 	for (i=0; i<PCI_EXT_CONF_LEN; i++) {
646 		buffer.peb_config[i] = pcibus.pb_read (tag, i*4);
647 	};
648 
649 	return copyout(&buffer, u, sizeof buffer);
650 }
651 
652 
653 static int
654 pci_internalize (struct proc *p, struct kern_devconf *kdcp, void *u, size_t s)
655 {
656 	return EOPNOTSUPP;
657 }
658 
659 /*-----------------------------------------------------------------------
660 **
661 **	Map pci interrupts to isa interrupts.
662 **
663 **-----------------------------------------------------------------------
664 */
665 
666 int pci_map_int (pcici_t tag, int(*func)(), void* arg, unsigned* maskptr)
667 {
668 	int irq, result;
669 
670 	irq = PCI_INTERRUPT_LINE_EXTRACT(
671 		pcibus.pb_read (tag, PCI_INTERRUPT_REG));
672 
673 	if (irq >= 16 || irq <= 0) {
674 		printf ("pci_map_int failed: no int line set.\n");
675 		return (0);
676 	}
677 
678 	result = pcibus.pb_regint (tag, func, arg, maskptr);
679 
680 	if (!result) {
681 		printf ("pci_map_int failed.\n");
682 		return (0);
683 	};
684 
685 	return (1);
686 }
687 
688 /*-----------------------------------------------------------
689 **
690 **	Display of unknown devices.
691 **
692 **-----------------------------------------------------------
693 */
694 struct vt {
695 	u_short	ident;
696 	char*	name;
697 };
698 
699 static struct vt VendorTable[] = {
700 	{0x1002, "ATI TECHNOLOGIES INC"},
701 	{0x1011, "DIGITAL EQUIPMENT CORPORATION"},
702 	{0x101A, "NCR"},
703 	{0x102B, "MATROX"},
704 	{0x1045, "OPTI"},
705 	{0x5333, "S3 INC."},
706 	{0x8086, "INTEL CORPORATION"},
707 	{0,0}
708 };
709 
710 static const char *const majclasses[] = {
711 	"old", "storage", "network", "display",
712 	"multimedia", "memory", "bridge"
713 };
714 
715 void not_supported (pcici_t tag, u_long type)
716 {
717 	u_char	reg;
718 	u_long	data;
719 	struct vt * vp;
720 
721 	/*
722 	**	lookup the names.
723 	*/
724 
725 	for (vp=VendorTable; vp->ident; vp++)
726 		if (vp->ident == (type & 0xffff))
727 			break;
728 
729 	/*
730 	**	and display them.
731 	*/
732 
733 	if (vp->ident) printf (vp->name);
734 		else   printf ("vendor=0x%lx", type & 0xffff);
735 
736 	printf (", device=0x%lx", type >> 16);
737 
738 	data = (pcibus.pb_read(tag, PCI_CLASS_REG) >> 24) & 0xff;
739 	if (data < sizeof(majclasses) / sizeof(majclasses[0]))
740 		printf(", class=%s", majclasses[data]);
741 
742 	printf (" [not supported]\n");
743 
744 	for (reg=PCI_MAP_REG_START; reg<PCI_MAP_REG_END; reg+=4) {
745 		data = pcibus.pb_read (tag, reg);
746 		if (!data) continue;
747 		switch (data&7) {
748 
749 		case 1:
750 		case 5:
751 			printf ("	map(%x): io(%lx)\n",
752 				reg, data & ~3);
753 			break;
754 		case 0:
755 			printf ("	map(%x): mem32(%lx)\n",
756 				reg, data & ~7);
757 			break;
758 		case 2:
759 			printf ("	map(%x): mem20(%lx)\n",
760 				reg, data & ~7);
761 			break;
762 		case 4:
763 			printf ("	map(%x): mem64(%lx)\n",
764 				reg, data & ~7);
765 			break;
766 		}
767 	}
768 }
769 
770 #ifndef __FreeBSD2__
771 /*-----------------------------------------------------------
772 **
773 **	Mapping of physical to virtual memory
774 **
775 **-----------------------------------------------------------
776 */
777 
778 extern vm_map_t kernel_map;
779 
780 static	vm_offset_t pmap_mapdev (vm_offset_t paddr, vm_size_t vsize)
781 {
782 	vm_offset_t	vaddr,value;
783 	u_long		result;
784 
785 	vaddr  = vm_map_min (kernel_map);
786 
787 	result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0,
788 				&vaddr, vsize, TRUE);
789 
790 	if (result != KERN_SUCCESS) {
791 		printf (" vm_map_find failed(%d)\n", result);
792 		return (0);
793 	};
794 
795 	/*
796 	**	map physical
797 	*/
798 
799 	value = vaddr;
800 	while (vsize >= NBPG) {
801 		pmap_enter (pmap_kernel(), vaddr, paddr,
802 				VM_PROT_READ|VM_PROT_WRITE, TRUE);
803 		vaddr += NBPG;
804 		paddr += NBPG;
805 		vsize -= NBPG;
806 	};
807 	return (value);
808 }
809 
810 /*------------------------------------------------------------
811 **
812 **	Emulate the register_intr() function of FreeBSD 2.0
813 **
814 **	requires a patch:
815 **	FreeBSD 2.0:	"/sys/i386/isa/vector.s"
816 **	386bsd0.1:	"/sys/i386/isa/icu.s"
817 **	386bsd1.0:	Please ask Jesus Monroy Jr.
818 **
819 **------------------------------------------------------------
820 */
821 
822 #include <machine/segments.h>
823 
824 int		pci_int_unit [16];
825 inthand2_t*    (pci_int_hdlr [16]);
826 unsigned int *	pci_int_mptr [16];
827 unsigned int	pci_int_count[16];
828 
829 extern void
830 	Vpci3(), Vpci4(), Vpci5(), Vpci6(), Vpci7(), Vpci8(), Vpci9(),
831 	Vpci10(), Vpci11(), Vpci12(), Vpci13(), Vpci14(), Vpci15();
832 
833 static inthand_t* pci_int_glue[16] = {
834 	0, 0, 0, Vpci3, Vpci4, Vpci5, Vpci6, Vpci7, Vpci8,
835 	Vpci9, Vpci10, Vpci11, Vpci12, Vpci13, Vpci14, Vpci15 };
836 
837 static int
838 register_intr __P((int intr, int device_id, unsigned int flags,
839 		       inthand2_t *handler, unsigned int* mptr, int unit))
840 {
841 	if (intr >= 16 || intr <= 2)
842 		return (EINVAL);
843 	if (pci_int_hdlr [intr])
844 		return (EBUSY);
845 
846 	pci_int_hdlr [intr] = handler;
847 	pci_int_unit [intr] = unit;
848 	pci_int_mptr [intr] = mptr;
849 
850 	setidt(NRSVIDT + intr, pci_int_glue[intr], SDT_SYS386IGT, SEL_KPL);
851 	return (0);
852 }
853 #endif /* __FreeBSD2__ */
854 #endif /* NPCI */
855