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