xref: /freebsd/sys/i386/pci/pci_pir.c (revision ae83180158c4c937f170e31eff311b18c0286a93)
1 /*
2  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3  * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
4  * Copyright (c) 2000, BSDi
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice unmodified, this list of conditions, and the following
12  *    disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  *
30  */
31 
32 #include <sys/param.h>		/* XXX trim includes */
33 #include <sys/systm.h>
34 #include <sys/bus.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 #include <sys/malloc.h>
38 #include <vm/vm.h>
39 #include <vm/pmap.h>
40 #include <machine/md_var.h>
41 #include <dev/pci/pcivar.h>
42 #include <dev/pci/pcireg.h>
43 #include <isa/isavar.h>
44 #include <machine/nexusvar.h>
45 #include <machine/pci_cfgreg.h>
46 #include <machine/segments.h>
47 #include <machine/pc/bios.h>
48 
49 #ifdef APIC_IO
50 #include <machine/smp.h>
51 #endif /* APIC_IO */
52 
53 #include "pcib_if.h"
54 
55 #define PRVERB(a) printf a
56 
57 static int cfgmech;
58 static int devmax;
59 static int usebios;
60 static int enable_pcibios = 0;
61 
62 TUNABLE_INT("hw.pci.enable_pcibios", &enable_pcibios);
63 
64 static int	pci_cfgintr_unique(struct PIR_entry *pe, int pin);
65 static int	pci_cfgintr_linked(struct PIR_entry *pe, int pin);
66 static int	pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin);
67 static int	pci_cfgintr_virgin(struct PIR_entry *pe, int pin);
68 
69 static int	pcibios_cfgread(int bus, int slot, int func, int reg, int bytes);
70 static void	pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
71 static int	pcibios_cfgopen(void);
72 static int	pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
73 static void	pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
74 static int	pcireg_cfgopen(void);
75 
76 static struct PIR_table	*pci_route_table;
77 static int		pci_route_count;
78 
79 /*
80  * Some BIOS writers seem to want to ignore the spec and put
81  * 0 in the intline rather than 255 to indicate none.  Some use
82  * numbers in the range 128-254 to indicate something strange and
83  * apparently undocumented anywhere.  Assume these are completely bogus
84  * and map them to 255, which means "none".
85  */
86 static __inline__ int
87 pci_i386_map_intline(int line)
88 {
89 	if (line == 0 || line >= 128)
90 		return (PCI_INVALID_IRQ);
91 	return (line);
92 }
93 
94 int
95 pci_pcibios_active(void)
96 {
97 	return (usebios);
98 }
99 
100 int
101 pci_kill_pcibios(void)
102 {
103 	usebios = 0;
104 	return (pcireg_cfgopen() != 0);
105 }
106 
107 static u_int16_t
108 pcibios_get_version(void)
109 {
110 	struct bios_regs args;
111 
112 	if (PCIbios.entry == 0) {
113 		PRVERB(("pcibios: No call entry point\n"));
114 		return (0);
115 	}
116 	args.eax = PCIBIOS_BIOS_PRESENT;
117 	if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
118 		PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
119 		return (0);
120 	}
121 	if (args.edx != 0x20494350) {
122 		PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
123 		return (0);
124 	}
125 	return (args.ebx & 0xffff);
126 }
127 
128 /*
129  * Initialise access to PCI configuration space
130  */
131 int
132 pci_cfgregopen(void)
133 {
134 	static int		opened = 0;
135 	u_long			sigaddr;
136 	static struct PIR_table	*pt;
137 	u_int8_t		ck, *cv;
138 	int			i;
139 
140 	if (opened)
141 		return(1);
142 
143 	if (pcibios_cfgopen() != 0)
144 		usebios = 1;
145 	else if (pcireg_cfgopen() != 0)
146 		usebios = 0;
147 	else
148 		return(0);
149 
150 	/*
151 	 * Look for the interrupt routing table.
152 	 *
153 	 * We use PCI BIOS's PIR table if it's available $PIR is the
154 	 * standard way to do this.  Sadly, some machines are not
155 	 * standards conforming and have _PIR instead.  We shrug and cope
156 	 * by looking for both.
157 	 */
158 	if (pcibios_get_version() >= 0x0210 && pt == NULL) {
159 		sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0);
160 		if (sigaddr == 0)
161 			sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
162 		if (sigaddr != 0) {
163 			pt = (struct PIR_table *)(uintptr_t)
164 			    BIOS_PADDRTOVADDR(sigaddr);
165 			for (cv = (u_int8_t *)pt, ck = 0, i = 0;
166 			     i < (pt->pt_header.ph_length); i++) {
167 				ck += cv[i];
168 			}
169 			if (ck == 0) {
170 				pci_route_table = pt;
171 				pci_route_count = (pt->pt_header.ph_length -
172 				    sizeof(struct PIR_header)) /
173 				    sizeof(struct PIR_entry);
174 				printf("Using $PIR table, %d entries at %p\n",
175 				    pci_route_count, pci_route_table);
176 			}
177 		}
178 	}
179 	opened = 1;
180 	return(1);
181 }
182 
183 /*
184  * Read configuration space register
185  */
186 static u_int32_t
187 pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes)
188 {
189 	return(usebios ?
190 	    pcibios_cfgread(bus, slot, func, reg, bytes) :
191 	    pcireg_cfgread(bus, slot, func, reg, bytes));
192 }
193 
194 u_int32_t
195 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
196 {
197 	uint32_t line;
198 #ifdef APIC_IO
199 	uint32_t pin;
200 
201 	/*
202 	 * If we are using the APIC, the contents of the intline
203 	 * register will probably be wrong (since they are set up for
204 	 * use with the PIC.  Rather than rewrite these registers
205 	 * (maybe that would be smarter) we trap attempts to read them
206 	 * and translate to our private vector numbers.
207 	 */
208 	if ((reg == PCIR_INTLINE) && (bytes == 1)) {
209 
210 		pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1);
211 		line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1);
212 
213 		if (pin != 0) {
214 			int airq;
215 
216 			airq = pci_apic_irq(bus, slot, pin);
217 			if (airq >= 0) {
218 				/* PCI specific entry found in MP table */
219 				if (airq != line)
220 					undirect_pci_irq(line);
221 				return(airq);
222 			} else {
223 				/*
224 				 * PCI interrupts might be redirected
225 				 * to the ISA bus according to some MP
226 				 * tables. Use the same methods as
227 				 * used by the ISA devices devices to
228 				 * find the proper IOAPIC int pin.
229 				 */
230 				airq = isa_apic_irq(line);
231 				if ((airq >= 0) && (airq != line)) {
232 					/* XXX: undirect_pci_irq() ? */
233 					undirect_isa_irq(line);
234 					return(airq);
235 				}
236 			}
237 		}
238 		return(line);
239 	}
240 #else
241 	/*
242 	 * Some BIOS writers seem to want to ignore the spec and put
243 	 * 0 in the intline rather than 255 to indicate none.  The rest of
244 	 * the code uses 255 as an invalid IRQ.
245 	 */
246 	if (reg == PCIR_INTLINE && bytes == 1) {
247 		line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1);
248 		return pci_i386_map_intline(line);
249 	}
250 #endif /* APIC_IO */
251 	return(pci_do_cfgregread(bus, slot, func, reg, bytes));
252 }
253 
254 /*
255  * Write configuration space register
256  */
257 void
258 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
259 {
260     return (usebios ?
261 	pcibios_cfgwrite(bus, slot, func, reg, data, bytes) :
262 	pcireg_cfgwrite(bus, slot, func, reg, data, bytes));
263 }
264 
265 /*
266  * Route a PCI interrupt
267  *
268  * XXX we don't do anything "right" with the function number in the PIR table
269  *     (because the consumer isn't currently passing it in).  We don't care
270  *     anyway, due to the way PCI interrupts are assigned.
271  */
272 int
273 pci_cfgintr(int bus, int device, int pin)
274 {
275 	struct PIR_entry	*pe;
276 	int			i, irq;
277 	struct bios_regs	args;
278 	u_int16_t		v;
279 	int already = 0;
280 
281 	v = pcibios_get_version();
282 	if (v < 0x0210) {
283 		PRVERB((
284 		"pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n",
285 		    (v & 0xff00) >> 8, v & 0xff));
286 		return (PCI_INVALID_IRQ);
287 	}
288 	if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
289 	    (pin < 1) || (pin > 4))
290 		return(PCI_INVALID_IRQ);
291 
292 	/*
293 	 * Scan the entry table for a contender
294 	 */
295 	for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count;
296 	     i++, pe++) {
297 		if ((bus != pe->pe_bus) || (device != pe->pe_device))
298 			continue;
299 
300 		irq = pci_cfgintr_linked(pe, pin);
301 		if (irq == PCI_INVALID_IRQ)
302 			irq = pci_cfgintr_unique(pe, pin);
303 		if (irq != PCI_INVALID_IRQ)
304 			already = 1;
305 		if (irq == PCI_INVALID_IRQ)
306 			irq = pci_cfgintr_virgin(pe, pin);
307 		if (irq == PCI_INVALID_IRQ)
308 			break;
309 
310 		/*
311 		 * Ask the BIOS to route the interrupt
312 		 */
313 		args.eax = PCIBIOS_ROUTE_INTERRUPT;
314 		args.ebx = (bus << 8) | (device << 3);
315 		/* pin value is 0xa - 0xd */
316 		args.ecx = (irq << 8) | (0xa + pin - 1);
317 		if (!already &&
318 		    bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
319 			/*
320 			 * XXX if it fails, we should try to smack the router
321 			 * hardware directly.
322 			 * XXX Also, there may be other choices that we can
323 			 * try that will work.
324 			 */
325 			PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n"));
326 			return(PCI_INVALID_IRQ);
327 		}
328 		printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus,
329 		    device, 'A' + pin - 1, irq);
330 		return(irq);
331 	}
332 
333 	PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus,
334 	    device, 'A' + pin - 1));
335 	return(PCI_INVALID_IRQ);
336 }
337 
338 /*
339  * Look to see if the routing table claims this pin is uniquely routed.
340  */
341 static int
342 pci_cfgintr_unique(struct PIR_entry *pe, int pin)
343 {
344 	int		irq;
345 	uint32_t	irqmask;
346 
347 	irqmask = pe->pe_intpin[pin - 1].irqs;
348 	if (irqmask != 0 && powerof2(irqmask)) {
349 		irq = ffs(irqmask) - 1;
350 		PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq));
351 		return(irq);
352 	}
353 	return(PCI_INVALID_IRQ);
354 }
355 
356 /*
357  * Look for another device which shares the same link byte and
358  * already has a unique IRQ, or which has had one routed already.
359  */
360 static int
361 pci_cfgintr_linked(struct PIR_entry *pe, int pin)
362 {
363 	struct PIR_entry	*oe;
364 	struct PIR_intpin	*pi;
365 	int			i, j, irq;
366 
367 	/*
368 	 * Scan table slots.
369 	 */
370 	for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count;
371 	     i++, oe++) {
372 		/* scan interrupt pins */
373 		for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
374 
375 			/* don't look at the entry we're trying to match */
376 			if ((pe == oe) && (i == (pin - 1)))
377 				continue;
378 			/* compare link bytes */
379 			if (pi->link != pe->pe_intpin[pin - 1].link)
380 				continue;
381 			/* link destination mapped to a unique interrupt? */
382 			if (pi->irqs != 0 && powerof2(pi->irqs)) {
383 				irq = ffs(pi->irqs) - 1;
384 				PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
385 				    pi->link, irq));
386 				return(irq);
387 			}
388 
389 			/*
390 			 * look for the real PCI device that matches this
391 			 * table entry
392 			 */
393 			irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device,
394 			    j, pin);
395 			if (irq != PCI_INVALID_IRQ)
396 				return(irq);
397 		}
398 	}
399 	return(PCI_INVALID_IRQ);
400 }
401 
402 /*
403  * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
404  * see if it has already been assigned an interrupt.
405  */
406 static int
407 pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
408 {
409 	devclass_t		pci_devclass;
410 	device_t		*pci_devices;
411 	int			pci_count;
412 	device_t		*pci_children;
413 	int			pci_childcount;
414 	device_t		*busp, *childp;
415 	int			i, j, irq;
416 
417 	/*
418 	 * Find all the PCI busses.
419 	 */
420 	pci_count = 0;
421 	if ((pci_devclass = devclass_find("pci")) != NULL)
422 		devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
423 
424 	/*
425 	 * Scan all the PCI busses/devices looking for this one.
426 	 */
427 	irq = PCI_INVALID_IRQ;
428 	for (i = 0, busp = pci_devices; (i < pci_count) && (irq == PCI_INVALID_IRQ);
429 	     i++, busp++) {
430 		pci_childcount = 0;
431 		device_get_children(*busp, &pci_children, &pci_childcount);
432 
433 		for (j = 0, childp = pci_children; j < pci_childcount; j++,
434 		    childp++) {
435 			if ((pci_get_bus(*childp) == bus) &&
436 			    (pci_get_slot(*childp) == device) &&
437 			    (pci_get_intpin(*childp) == matchpin)) {
438 				irq = pci_i386_map_intline(pci_get_irq(*childp));
439 				if (irq != PCI_INVALID_IRQ)
440 					PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
441 					    pe->pe_intpin[pin - 1].link, irq,
442 					    pci_get_bus(*childp),
443 					    pci_get_slot(*childp),
444 					    pci_get_function(*childp)));
445 				break;
446 			}
447 		}
448 		if (pci_children != NULL)
449 			free(pci_children, M_TEMP);
450 	}
451 	if (pci_devices != NULL)
452 		free(pci_devices, M_TEMP);
453 	return(irq);
454 }
455 
456 /*
457  * Pick a suitable IRQ from those listed as routable to this device.
458  */
459 static int
460 pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
461 {
462 	int		irq, ibit;
463 
464 	/*
465 	 * first scan the set of PCI-only interrupts and see if any of these
466 	 * are routable
467 	 */
468 	for (irq = 0; irq < 16; irq++) {
469 		ibit = (1 << irq);
470 
471 		/* can we use this interrupt? */
472 		if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
473 		    (pe->pe_intpin[pin - 1].irqs & ibit)) {
474 			PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq));
475 			return(irq);
476 		}
477 	}
478 
479 	/* life is tough, so just pick an interrupt */
480 	for (irq = 0; irq < 16; irq++) {
481 		ibit = (1 << irq);
482 		if (pe->pe_intpin[pin - 1].irqs & ibit) {
483 			PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq));
484 			return(irq);
485 		}
486 	}
487 	return(PCI_INVALID_IRQ);
488 }
489 
490 
491 /*
492  * Config space access using BIOS functions
493  */
494 static int
495 pcibios_cfgread(int bus, int slot, int func, int reg, int bytes)
496 {
497 	struct bios_regs args;
498 	u_int mask;
499 
500 	switch(bytes) {
501 	case 1:
502 		args.eax = PCIBIOS_READ_CONFIG_BYTE;
503 		mask = 0xff;
504 		break;
505 	case 2:
506 		args.eax = PCIBIOS_READ_CONFIG_WORD;
507 		mask = 0xffff;
508 		break;
509 	case 4:
510 		args.eax = PCIBIOS_READ_CONFIG_DWORD;
511 		mask = 0xffffffff;
512 		break;
513 	default:
514 		return(-1);
515 	}
516 	args.ebx = (bus << 8) | (slot << 3) | func;
517 	args.edi = reg;
518 	bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
519 	/* check call results? */
520 	return(args.ecx & mask);
521 }
522 
523 static void
524 pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
525 {
526 	struct bios_regs args;
527 
528 	switch(bytes) {
529 	case 1:
530 		args.eax = PCIBIOS_WRITE_CONFIG_BYTE;
531 		break;
532 	case 2:
533 		args.eax = PCIBIOS_WRITE_CONFIG_WORD;
534 		break;
535 	case 4:
536 		args.eax = PCIBIOS_WRITE_CONFIG_DWORD;
537 		break;
538 	default:
539 		return;
540 	}
541 	args.ebx = (bus << 8) | (slot << 3) | func;
542 	args.ecx = data;
543 	args.edi = reg;
544 	bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
545 }
546 
547 /*
548  * Determine whether there is a PCI BIOS present
549  */
550 static int
551 pcibios_cfgopen(void)
552 {
553 	u_int16_t		v = 0;
554 
555 	if (PCIbios.entry != 0 && enable_pcibios) {
556 		v = pcibios_get_version();
557 		if (v > 0)
558 			printf("pcibios: BIOS version %x.%02x\n",
559 			    (v & 0xff00) >> 8, v & 0xff);
560 	}
561 	return (v > 0);
562 }
563 
564 /*
565  * Configuration space access using direct register operations
566  */
567 
568 /* enable configuration space accesses and return data port address */
569 static int
570 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
571 {
572 	int dataport = 0;
573 
574 	if (bus <= PCI_BUSMAX
575 	    && slot < devmax
576 	    && func <= PCI_FUNCMAX
577 	    && reg <= PCI_REGMAX
578 	    && bytes != 3
579 	    && (unsigned) bytes <= 4
580 	    && (reg & (bytes -1)) == 0) {
581 		switch (cfgmech) {
582 		case 1:
583 			outl(CONF1_ADDR_PORT, (1 << 31)
584 			    | (bus << 16) | (slot << 11)
585 			    | (func << 8) | (reg & ~0x03));
586 			dataport = CONF1_DATA_PORT + (reg & 0x03);
587 			break;
588 		case 2:
589 			outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
590 			outb(CONF2_FORWARD_PORT, bus);
591 			dataport = 0xc000 | (slot << 8) | reg;
592 			break;
593 		}
594 	}
595 	return (dataport);
596 }
597 
598 /* disable configuration space accesses */
599 static void
600 pci_cfgdisable(void)
601 {
602 	switch (cfgmech) {
603 	case 1:
604 		outl(CONF1_ADDR_PORT, 0);
605 		break;
606 	case 2:
607 		outb(CONF2_ENABLE_PORT, 0);
608 		outb(CONF2_FORWARD_PORT, 0);
609 		break;
610 	}
611 }
612 
613 static int
614 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
615 {
616 	int data = -1;
617 	int port;
618 
619 	port = pci_cfgenable(bus, slot, func, reg, bytes);
620 
621 	if (port != 0) {
622 		switch (bytes) {
623 		case 1:
624 			data = inb(port);
625 			break;
626 		case 2:
627 			data = inw(port);
628 			break;
629 		case 4:
630 			data = inl(port);
631 			break;
632 		}
633 		pci_cfgdisable();
634 	}
635 	return (data);
636 }
637 
638 static void
639 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
640 {
641 	int port;
642 
643 	port = pci_cfgenable(bus, slot, func, reg, bytes);
644 	if (port != 0) {
645 		switch (bytes) {
646 		case 1:
647 			outb(port, data);
648 			break;
649 		case 2:
650 			outw(port, data);
651 			break;
652 		case 4:
653 			outl(port, data);
654 			break;
655 		}
656 		pci_cfgdisable();
657 	}
658 }
659 
660 /* check whether the configuration mechanism has been correctly identified */
661 static int
662 pci_cfgcheck(int maxdev)
663 {
664 	u_char device;
665 
666 	if (bootverbose)
667 		printf("pci_cfgcheck:\tdevice ");
668 
669 	for (device = 0; device < maxdev; device++) {
670 		unsigned id, class, header;
671 		if (bootverbose)
672 			printf("%d ", device);
673 
674 		id = inl(pci_cfgenable(0, device, 0, 0, 4));
675 		if (id == 0 || id == -1)
676 			continue;
677 
678 		class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
679 		if (bootverbose)
680 			printf("[class=%06x] ", class);
681 		if (class == 0 || (class & 0xf870ff) != 0)
682 			continue;
683 
684 		header = inb(pci_cfgenable(0, device, 0, 14, 1));
685 		if (bootverbose)
686 			printf("[hdr=%02x] ", header);
687 		if ((header & 0x7e) != 0)
688 			continue;
689 
690 		if (bootverbose)
691 			printf("is there (id=%08x)\n", id);
692 
693 		pci_cfgdisable();
694 		return (1);
695 	}
696 	if (bootverbose)
697 		printf("-- nothing found\n");
698 
699 	pci_cfgdisable();
700 	return (0);
701 }
702 
703 static int
704 pcireg_cfgopen(void)
705 {
706 	unsigned long mode1res,oldval1;
707 	unsigned char mode2res,oldval2;
708 
709 	oldval1 = inl(CONF1_ADDR_PORT);
710 
711 	if (bootverbose) {
712 		printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
713 		    oldval1);
714 	}
715 
716 	if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
717 
718 		cfgmech = 1;
719 		devmax = 32;
720 
721 		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
722 		outb(CONF1_ADDR_PORT +3, 0);
723 		mode1res = inl(CONF1_ADDR_PORT);
724 		outl(CONF1_ADDR_PORT, oldval1);
725 
726 		if (bootverbose)
727 			printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n",
728 			    mode1res, CONF1_ENABLE_CHK);
729 
730 		if (mode1res) {
731 			if (pci_cfgcheck(32))
732 				return (cfgmech);
733 		}
734 
735 		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
736 		mode1res = inl(CONF1_ADDR_PORT);
737 		outl(CONF1_ADDR_PORT, oldval1);
738 
739 		if (bootverbose)
740 			printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n",
741 			    mode1res, CONF1_ENABLE_CHK1);
742 
743 		if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
744 			if (pci_cfgcheck(32))
745 				return (cfgmech);
746 		}
747 	}
748 
749 	oldval2 = inb(CONF2_ENABLE_PORT);
750 
751 	if (bootverbose) {
752 		printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
753 		    oldval2);
754 	}
755 
756 	if ((oldval2 & 0xf0) == 0) {
757 
758 		cfgmech = 2;
759 		devmax = 16;
760 
761 		outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
762 		mode2res = inb(CONF2_ENABLE_PORT);
763 		outb(CONF2_ENABLE_PORT, oldval2);
764 
765 		if (bootverbose)
766 			printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
767 			    mode2res, CONF2_ENABLE_CHK);
768 
769 		if (mode2res == CONF2_ENABLE_RES) {
770 			if (bootverbose)
771 				printf("pci_open(2a):\tnow trying mechanism 2\n");
772 
773 			if (pci_cfgcheck(16))
774 				return (cfgmech);
775 		}
776 	}
777 
778 	cfgmech = 0;
779 	devmax = 0;
780 	return (cfgmech);
781 }
782 
783