xref: /freebsd/sys/amd64/pci/pci_cfgreg.c (revision 6990ffd8a95caaba6858ad44ff1b3157d1efba8f)
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 <pci/pcivar.h>
42 #include <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 int
80 pci_pcibios_active(void)
81 {
82     return usebios;
83 }
84 
85 int
86 pci_kill_pcibios(void)
87 {
88     usebios = 0;
89     return pcireg_cfgopen() != 0;
90 }
91 
92 static u_int16_t
93 pcibios_get_version(void)
94 {
95     struct bios_regs args;
96 
97     if (PCIbios.entry == 0) {
98 	PRVERB(("pcibios: No call entry point\n"));
99 	return (0);
100     }
101     args.eax = PCIBIOS_BIOS_PRESENT;
102     if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
103 	PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
104 	return (0);
105     }
106     if (args.edx != 0x20494350) {
107 	PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
108 	return (0);
109     }
110     return (args.ebx & 0xffff);
111 }
112 
113 /*
114  * Initialise access to PCI configuration space
115  */
116 int
117 pci_cfgregopen(void)
118 {
119     static int			opened = 0;
120     u_long			sigaddr;
121     static struct PIR_table	*pt;
122     u_int8_t			ck, *cv;
123     int				i;
124 
125     if (opened)
126 	return(1);
127 
128     if (pcibios_cfgopen() != 0) {
129 	usebios = 1;
130     } else if (pcireg_cfgopen() != 0) {
131 	usebios = 0;
132     } else {
133 	return(0);
134     }
135 
136     /*
137      * Look for the interrupt routing table.
138      */
139     /* We use PCI BIOS's PIR table if it's available */
140     if (pcibios_get_version() >= 0x0210 && pt == NULL &&
141       (sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0)) != 0) {
142 	pt = (struct PIR_table *)(uintptr_t)BIOS_PADDRTOVADDR(sigaddr);
143 	for (cv = (u_int8_t *)pt, ck = 0, i = 0; i < (pt->pt_header.ph_length); i++) {
144 	    ck += cv[i];
145 	}
146 	if (ck == 0) {
147 	    pci_route_table = pt;
148 	    pci_route_count = (pt->pt_header.ph_length - sizeof(struct PIR_header)) / sizeof(struct PIR_entry);
149 	    printf("Using $PIR table, %d entries at %p\n", pci_route_count, pci_route_table);
150 	}
151     }
152 
153     opened = 1;
154     return(1);
155 }
156 
157 /*
158  * Read configuration space register
159  */
160 static u_int32_t
161 pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes)
162 {
163     return(usebios ?
164 	   pcibios_cfgread(bus, slot, func, reg, bytes) :
165 	   pcireg_cfgread(bus, slot, func, reg, bytes));
166 }
167 
168 u_int32_t
169 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
170 {
171 #ifdef APIC_IO
172     /*
173      * If we are using the APIC, the contents of the intline register will probably
174      * be wrong (since they are set up for use with the PIC.
175      * Rather than rewrite these registers (maybe that would be smarter) we trap
176      * attempts to read them and translate to our private vector numbers.
177      */
178     if ((reg == PCIR_INTLINE) && (bytes == 1)) {
179 	int	pin, line;
180 
181 	pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1);
182 	line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1);
183 
184 	if (pin != 0) {
185 	    int airq;
186 
187 	    airq = pci_apic_irq(bus, slot, pin);
188 	    if (airq >= 0) {
189 		/* PCI specific entry found in MP table */
190 		if (airq != line)
191 		    undirect_pci_irq(line);
192 		return(airq);
193 	    } else {
194 		/*
195 		 * PCI interrupts might be redirected to the
196 		 * ISA bus according to some MP tables. Use the
197 		 * same methods as used by the ISA devices
198 		 * devices to find the proper IOAPIC int pin.
199 		 */
200 		airq = isa_apic_irq(line);
201 		if ((airq >= 0) && (airq != line)) {
202 		    /* XXX: undirect_pci_irq() ? */
203 		    undirect_isa_irq(line);
204 		    return(airq);
205 		}
206 	    }
207 	}
208 	return(line);
209     }
210 #endif /* APIC_IO */
211     return(pci_do_cfgregread(bus, slot, func, reg, bytes));
212 }
213 
214 /*
215  * Write configuration space register
216  */
217 void
218 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
219 {
220     return(usebios ?
221 	   pcibios_cfgwrite(bus, slot, func, reg, data, bytes) :
222 	   pcireg_cfgwrite(bus, slot, func, reg, data, bytes));
223 }
224 
225 /*
226  * Route a PCI interrupt
227  *
228  * XXX we don't do anything "right" with the function number in the PIR table
229  *     (because the consumer isn't currently passing it in).  We don't care
230  *     anyway, due to the way PCI interrupts are assigned.
231  */
232 int
233 pci_cfgintr(int bus, int device, int pin)
234 {
235     struct PIR_entry	*pe;
236     int			i, irq;
237     struct bios_regs	args;
238     u_int16_t		v;
239     int already = 0;
240 
241     v = pcibios_get_version();
242     if (v < 0x0210) {
243 	PRVERB((
244 	  "pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n",
245 	  (v & 0xff00) >> 8, v & 0xff));
246 	return (255);
247     }
248     if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
249       (pin < 1) || (pin > 4))
250 	return(255);
251 
252     /*
253      * Scan the entry table for a contender
254      */
255     for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, pe++) {
256 	if ((bus != pe->pe_bus) || (device != pe->pe_device))
257 	    continue;
258 
259 	irq = pci_cfgintr_linked(pe, pin);
260 	if (irq != 255)
261 	     already = 1;
262 	if (irq == 255)
263 	    irq = pci_cfgintr_unique(pe, pin);
264 	if (irq == 255)
265 	    irq = pci_cfgintr_virgin(pe, pin);
266 
267 	if (irq == 255)
268 	    break;
269 
270 	/*
271 	 * Ask the BIOS to route the interrupt
272 	 */
273 	args.eax = PCIBIOS_ROUTE_INTERRUPT;
274 	args.ebx = (bus << 8) | (device << 3);
275 	args.ecx = (irq << 8) | (0xa + pin - 1);	/* pin value is 0xa - 0xd */
276 	if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)) && !already) {
277 	    /*
278 	     * XXX if it fails, we should try to smack the router
279 	     * hardware directly.
280 	     * XXX Also, there may be other choices that we can try that
281 	     * will work.
282 	     */
283 	    PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n"));
284 	    return(255);
285 	}
286 	printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus, device, 'A' + pin - 1, irq);
287 	return(irq);
288     }
289 
290     PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus, device, 'A' + pin - 1));
291     return(255);
292 }
293 
294 /*
295  * Look to see if the routing table claims this pin is uniquely routed.
296  */
297 static int
298 pci_cfgintr_unique(struct PIR_entry *pe, int pin)
299 {
300     int		irq;
301 
302     if (powerof2(pe->pe_intpin[pin - 1].irqs)) {
303 	irq = ffs(pe->pe_intpin[pin - 1].irqs) - 1;
304 	PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq));
305 	return(irq);
306     }
307     return(255);
308 }
309 
310 /*
311  * Look for another device which shares the same link byte and
312  * already has a unique IRQ, or which has had one routed already.
313  */
314 static int
315 pci_cfgintr_linked(struct PIR_entry *pe, int pin)
316 {
317     struct PIR_entry	*oe;
318     struct PIR_intpin	*pi;
319     int			i, j, irq;
320 
321     /*
322      * Scan table slots.
323      */
324     for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count; i++, oe++) {
325 
326 	/* scan interrupt pins */
327 	for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
328 
329 	    /* don't look at the entry we're trying to match with */
330 	    if ((pe == oe) && (i == (pin - 1)))
331 		continue;
332 
333 	    /* compare link bytes */
334 	    if (pi->link != pe->pe_intpin[pin - 1].link)
335 		continue;
336 
337 	    /* link destination mapped to a unique interrupt? */
338 	    if (powerof2(pi->irqs)) {
339 		irq = ffs(pi->irqs) - 1;
340 		PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
341 		       pi->link, irq));
342 		return(irq);
343 	    }
344 
345 	    /* look for the real PCI device that matches this table entry */
346 	    if ((irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device, j, pin)) != 255)
347 		return(irq);
348 	}
349     }
350     return(255);
351 }
352 
353 /*
354  * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
355  * see if it has already been assigned an interrupt.
356  */
357 static int
358 pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
359 {
360     devclass_t		pci_devclass;
361     device_t		*pci_devices;
362     int			pci_count;
363     device_t		*pci_children;
364     int			pci_childcount;
365     device_t		*busp, *childp;
366     int			i, j, irq;
367 
368     /*
369      * Find all the PCI busses.
370      */
371     pci_count = 0;
372     if ((pci_devclass = devclass_find("pci")) != NULL)
373 	devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
374 
375     /*
376      * Scan all the PCI busses/devices looking for this one.
377      */
378     irq = 255;
379     for (i = 0, busp = pci_devices; (i < pci_count) && (irq == 255); i++, busp++) {
380 	pci_childcount = 0;
381 	device_get_children(*busp, &pci_children, &pci_childcount);
382 
383 	for (j = 0, childp = pci_children; j < pci_childcount; j++, childp++) {
384 	    if ((pci_get_bus(*childp) == bus) &&
385 		(pci_get_slot(*childp) == device) &&
386 		(pci_get_intpin(*childp) == matchpin) &&
387 		((irq = pci_get_irq(*childp)) != 255)) {
388 		PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
389 		       pe->pe_intpin[pin - 1].link, irq,
390 		       pci_get_bus(*childp), pci_get_slot(*childp), pci_get_function(*childp)));
391 		break;
392 	    }
393 	}
394 	if (pci_children != NULL)
395 	    free(pci_children, M_TEMP);
396     }
397     if (pci_devices != NULL)
398 	free(pci_devices, M_TEMP);
399     return(irq);
400 }
401 
402 /*
403  * Pick a suitable IRQ from those listed as routable to this device.
404  */
405 static int
406 pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
407 {
408     int		irq, ibit;
409 
410     /* first scan the set of PCI-only interrupts and see if any of these are routable */
411     for (irq = 0; irq < 16; irq++) {
412 	ibit = (1 << irq);
413 
414 	/* can we use this interrupt? */
415 	if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
416 	    (pe->pe_intpin[pin - 1].irqs & ibit)) {
417 	    PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq));
418 	    return(irq);
419 	}
420     }
421 
422     /* life is tough, so just pick an interrupt */
423     for (irq = 0; irq < 16; irq++) {
424 	ibit = (1 << irq);
425 
426 	if (pe->pe_intpin[pin - 1].irqs & ibit) {
427 	    PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq));
428 	    return(irq);
429 	}
430     }
431     return(255);
432 }
433 
434 
435 /*
436  * Config space access using BIOS functions
437  */
438 static int
439 pcibios_cfgread(int bus, int slot, int func, int reg, int bytes)
440 {
441     struct bios_regs args;
442     u_int mask;
443 
444     switch(bytes) {
445     case 1:
446 	args.eax = PCIBIOS_READ_CONFIG_BYTE;
447 	mask = 0xff;
448 	break;
449     case 2:
450 	args.eax = PCIBIOS_READ_CONFIG_WORD;
451 	mask = 0xffff;
452 	break;
453     case 4:
454 	args.eax = PCIBIOS_READ_CONFIG_DWORD;
455 	mask = 0xffffffff;
456 	break;
457     default:
458 	return(-1);
459     }
460     args.ebx = (bus << 8) | (slot << 3) | func;
461     args.edi = reg;
462     bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
463     /* check call results? */
464     return(args.ecx & mask);
465 }
466 
467 static void
468 pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
469 {
470     struct bios_regs args;
471 
472     switch(bytes) {
473     case 1:
474 	args.eax = PCIBIOS_WRITE_CONFIG_BYTE;
475 	break;
476     case 2:
477 	args.eax = PCIBIOS_WRITE_CONFIG_WORD;
478 	break;
479     case 4:
480 	args.eax = PCIBIOS_WRITE_CONFIG_DWORD;
481 	break;
482     default:
483 	return;
484     }
485     args.ebx = (bus << 8) | (slot << 3) | func;
486     args.ecx = data;
487     args.edi = reg;
488     bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
489 }
490 
491 /*
492  * Determine whether there is a PCI BIOS present
493  */
494 static int
495 pcibios_cfgopen(void)
496 {
497     u_int16_t		v = 0;
498 
499     if (PCIbios.entry != 0 && enable_pcibios) {
500 	v = pcibios_get_version();
501 	if (v > 0)
502 	    printf("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8,
503 	      v & 0xff);
504     }
505     return (v > 0);
506 }
507 
508 /*
509  * Configuration space access using direct register operations
510  */
511 
512 /* enable configuration space accesses and return data port address */
513 static int
514 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
515 {
516     int dataport = 0;
517 
518     if (bus <= PCI_BUSMAX
519 	&& slot < devmax
520 	&& func <= PCI_FUNCMAX
521 	&& reg <= PCI_REGMAX
522 	&& bytes != 3
523 	&& (unsigned) bytes <= 4
524 	&& (reg & (bytes -1)) == 0) {
525 	switch (cfgmech) {
526 	case 1:
527 	    outl(CONF1_ADDR_PORT, (1 << 31)
528 		 | (bus << 16) | (slot << 11)
529 		 | (func << 8) | (reg & ~0x03));
530 	    dataport = CONF1_DATA_PORT + (reg & 0x03);
531 	    break;
532 	case 2:
533 	    outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
534 	    outb(CONF2_FORWARD_PORT, bus);
535 	    dataport = 0xc000 | (slot << 8) | reg;
536 	    break;
537 	}
538     }
539     return (dataport);
540 }
541 
542 /* disable configuration space accesses */
543 static void
544 pci_cfgdisable(void)
545 {
546     switch (cfgmech) {
547     case 1:
548 	outl(CONF1_ADDR_PORT, 0);
549 	break;
550     case 2:
551 	outb(CONF2_ENABLE_PORT, 0);
552 	outb(CONF2_FORWARD_PORT, 0);
553 	break;
554     }
555 }
556 
557 static int
558 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
559 {
560     int data = -1;
561     int port;
562 
563     port = pci_cfgenable(bus, slot, func, reg, bytes);
564 
565     if (port != 0) {
566 	switch (bytes) {
567 	case 1:
568 	    data = inb(port);
569 	    break;
570 	case 2:
571 	    data = inw(port);
572 	    break;
573 	case 4:
574 	    data = inl(port);
575 	    break;
576 	}
577 	pci_cfgdisable();
578     }
579     return (data);
580 }
581 
582 static void
583 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
584 {
585     int port;
586 
587     port = pci_cfgenable(bus, slot, func, reg, bytes);
588     if (port != 0) {
589 	switch (bytes) {
590 	case 1:
591 	    outb(port, data);
592 	    break;
593 	case 2:
594 	    outw(port, data);
595 	    break;
596 	case 4:
597 	    outl(port, data);
598 	    break;
599 	}
600 	pci_cfgdisable();
601     }
602 }
603 
604 /* check whether the configuration mechanism has been correctly identified */
605 static int
606 pci_cfgcheck(int maxdev)
607 {
608     u_char device;
609 
610     if (bootverbose)
611 	printf("pci_cfgcheck:\tdevice ");
612 
613     for (device = 0; device < maxdev; device++) {
614 	unsigned id, class, header;
615 	if (bootverbose)
616 	    printf("%d ", device);
617 
618 	id = inl(pci_cfgenable(0, device, 0, 0, 4));
619 	if (id == 0 || id == -1)
620 	    continue;
621 
622 	class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
623 	if (bootverbose)
624 	    printf("[class=%06x] ", class);
625 	if (class == 0 || (class & 0xf870ff) != 0)
626 	    continue;
627 
628 	header = inb(pci_cfgenable(0, device, 0, 14, 1));
629 	if (bootverbose)
630 	    printf("[hdr=%02x] ", header);
631 	if ((header & 0x7e) != 0)
632 	    continue;
633 
634 	if (bootverbose)
635 	    printf("is there (id=%08x)\n", id);
636 
637 	pci_cfgdisable();
638 	return (1);
639     }
640     if (bootverbose)
641 	printf("-- nothing found\n");
642 
643     pci_cfgdisable();
644     return (0);
645 }
646 
647 static int
648 pcireg_cfgopen(void)
649 {
650     unsigned long mode1res,oldval1;
651     unsigned char mode2res,oldval2;
652 
653     oldval1 = inl(CONF1_ADDR_PORT);
654 
655     if (bootverbose) {
656 	printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
657 	       oldval1);
658     }
659 
660     if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
661 
662 	cfgmech = 1;
663 	devmax = 32;
664 
665 	outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
666 	outb(CONF1_ADDR_PORT +3, 0);
667 	mode1res = inl(CONF1_ADDR_PORT);
668 	outl(CONF1_ADDR_PORT, oldval1);
669 
670 	if (bootverbose)
671 	    printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n",
672 		   mode1res, CONF1_ENABLE_CHK);
673 
674 	if (mode1res) {
675 	    if (pci_cfgcheck(32))
676 		return (cfgmech);
677 	}
678 
679 	outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
680 	mode1res = inl(CONF1_ADDR_PORT);
681 	outl(CONF1_ADDR_PORT, oldval1);
682 
683 	if (bootverbose)
684 	    printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n",
685 		   mode1res, CONF1_ENABLE_CHK1);
686 
687 	if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
688 	    if (pci_cfgcheck(32))
689 		return (cfgmech);
690 	}
691     }
692 
693     oldval2 = inb(CONF2_ENABLE_PORT);
694 
695     if (bootverbose) {
696 	printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
697 	       oldval2);
698     }
699 
700     if ((oldval2 & 0xf0) == 0) {
701 
702 	cfgmech = 2;
703 	devmax = 16;
704 
705 	outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
706 	mode2res = inb(CONF2_ENABLE_PORT);
707 	outb(CONF2_ENABLE_PORT, oldval2);
708 
709 	if (bootverbose)
710 	    printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
711 		   mode2res, CONF2_ENABLE_CHK);
712 
713 	if (mode2res == CONF2_ENABLE_RES) {
714 	    if (bootverbose)
715 		printf("pci_open(2a):\tnow trying mechanism 2\n");
716 
717 	    if (pci_cfgcheck(16))
718 		return (cfgmech);
719 	}
720     }
721 
722     cfgmech = 0;
723     devmax = 0;
724     return (cfgmech);
725 }
726 
727