xref: /freebsd/sys/i386/pci/pci_cfgreg.c (revision 5264a94f3f154cedc10d96b149600e64403b8876)
1ac19f918SStefan Eßer /*
25bec6157SStefan Eßer  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
312a02d6eSMike Smith  * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
412a02d6eSMike Smith  * Copyright (c) 2000, BSDi
55bec6157SStefan Eßer  * All rights reserved.
65bec6157SStefan Eßer  *
75bec6157SStefan Eßer  * Redistribution and use in source and binary forms, with or without
85bec6157SStefan Eßer  * modification, are permitted provided that the following conditions
95bec6157SStefan Eßer  * are met:
105bec6157SStefan Eßer  * 1. Redistributions of source code must retain the above copyright
115bec6157SStefan Eßer  *    notice unmodified, this list of conditions, and the following
125bec6157SStefan Eßer  *    disclaimer.
135bec6157SStefan Eßer  * 2. Redistributions in binary form must reproduce the above copyright
145bec6157SStefan Eßer  *    notice, this list of conditions and the following disclaimer in the
155bec6157SStefan Eßer  *    documentation and/or other materials provided with the distribution.
165bec6157SStefan Eßer  *
175bec6157SStefan Eßer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
185bec6157SStefan Eßer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
195bec6157SStefan Eßer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
205bec6157SStefan Eßer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
215bec6157SStefan Eßer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
225bec6157SStefan Eßer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235bec6157SStefan Eßer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245bec6157SStefan Eßer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255bec6157SStefan Eßer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
265bec6157SStefan Eßer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275bec6157SStefan Eßer  *
28c3aac50fSPeter Wemm  * $FreeBSD$
295bec6157SStefan Eßer  *
30ac19f918SStefan Eßer  */
31ac19f918SStefan Eßer 
3212a02d6eSMike Smith #include <sys/param.h>		/* XXX trim includes */
335bec6157SStefan Eßer #include <sys/systm.h>
348dc26439SPeter Wemm #include <sys/bus.h>
358dc26439SPeter Wemm #include <sys/kernel.h>
362a50a6d7SMike Smith #include <sys/module.h>
37280b4748SPeter Wemm #include <sys/malloc.h>
3854c9005fSWarner Losh #include <vm/vm.h>
3954c9005fSWarner Losh #include <vm/pmap.h>
4054c9005fSWarner Losh #include <machine/md_var.h>
41e300f53cSWarner Losh #include <dev/pci/pcivar.h>
42e300f53cSWarner Losh #include <dev/pci/pcireg.h>
432a50a6d7SMike Smith #include <isa/isavar.h>
44b6c84078SPeter Wemm #include <machine/nexusvar.h>
4512a02d6eSMike Smith #include <machine/pci_cfgreg.h>
46300451c4SMike Smith #include <machine/segments.h>
47300451c4SMike Smith #include <machine/pc/bios.h>
48300451c4SMike Smith 
49bb0d0a8eSMike Smith #ifdef APIC_IO
50bb0d0a8eSMike Smith #include <machine/smp.h>
51bb0d0a8eSMike Smith #endif /* APIC_IO */
52bb0d0a8eSMike Smith 
5321c3015aSDoug Rabson #include "pcib_if.h"
5421c3015aSDoug Rabson 
55d626906bSWarner Losh #define PRVERB(a) printf a
56d626906bSWarner Losh 
575bec6157SStefan Eßer static int cfgmech;
585bec6157SStefan Eßer static int devmax;
59300451c4SMike Smith static int usebios;
600b9427deSWarner Losh static int enable_pcibios = 0;
610b9427deSWarner Losh 
620b9427deSWarner Losh TUNABLE_INT("hw.pci.enable_pcibios", &enable_pcibios);
63300451c4SMike Smith 
64099d058bSMike Smith static int	pci_cfgintr_unique(struct PIR_entry *pe, int pin);
65099d058bSMike Smith static int	pci_cfgintr_linked(struct PIR_entry *pe, int pin);
66099d058bSMike Smith static int	pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin);
67099d058bSMike Smith static int	pci_cfgintr_virgin(struct PIR_entry *pe, int pin);
68099d058bSMike Smith 
6912a02d6eSMike Smith static int	pcibios_cfgread(int bus, int slot, int func, int reg, int bytes);
7012a02d6eSMike Smith static void	pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
71300451c4SMike Smith static int	pcibios_cfgopen(void);
7212a02d6eSMike Smith static int	pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
7312a02d6eSMike Smith static void	pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
74300451c4SMike Smith static int	pcireg_cfgopen(void);
75300451c4SMike Smith 
76099d058bSMike Smith static struct PIR_table	*pci_route_table;
7754c9005fSWarner Losh static int		pci_route_count;
7854c9005fSWarner Losh 
798ce1ab3aSWarner Losh /*
808ce1ab3aSWarner Losh  * Some BIOS writers seem to want to ignore the spec and put
818ce1ab3aSWarner Losh  * 0 in the intline rather than 255 to indicate none.  Some use
828ce1ab3aSWarner Losh  * numbers in the range 128-254 to indicate something strange and
838ce1ab3aSWarner Losh  * apparently undocumented anywhere.  Assume these are completely bogus
848ce1ab3aSWarner Losh  * and map them to 255, which means "none".
858ce1ab3aSWarner Losh  */
868ce1ab3aSWarner Losh static __inline__ int
878ce1ab3aSWarner Losh pci_i386_map_intline(int line)
888ce1ab3aSWarner Losh {
898ce1ab3aSWarner Losh 	if (line == 0 || line >= 128)
90e300f53cSWarner Losh 		return (PCI_INVALID_IRQ);
918ce1ab3aSWarner Losh 	return (line);
928ce1ab3aSWarner Losh }
938ce1ab3aSWarner Losh 
94573be827SPeter Wemm int
95573be827SPeter Wemm pci_pcibios_active(void)
96573be827SPeter Wemm {
97e300f53cSWarner Losh 	return (usebios);
98573be827SPeter Wemm }
99573be827SPeter Wemm 
100573be827SPeter Wemm int
101573be827SPeter Wemm pci_kill_pcibios(void)
102573be827SPeter Wemm {
103573be827SPeter Wemm 	usebios = 0;
104e300f53cSWarner Losh 	return (pcireg_cfgopen() != 0);
105573be827SPeter Wemm }
106573be827SPeter Wemm 
107d626906bSWarner Losh static u_int16_t
108d626906bSWarner Losh pcibios_get_version(void)
109d626906bSWarner Losh {
110d626906bSWarner Losh 	struct bios_regs args;
111d626906bSWarner Losh 
1125264a94fSJohn Baldwin 	if (PCIbios.ventry == 0) {
113d626906bSWarner Losh 		PRVERB(("pcibios: No call entry point\n"));
114d626906bSWarner Losh 		return (0);
115d626906bSWarner Losh 	}
116d626906bSWarner Losh 	args.eax = PCIBIOS_BIOS_PRESENT;
117d626906bSWarner Losh 	if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
118d626906bSWarner Losh 		PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
119d626906bSWarner Losh 		return (0);
120d626906bSWarner Losh 	}
121d626906bSWarner Losh 	if (args.edx != 0x20494350) {
122d626906bSWarner Losh 		PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
123d626906bSWarner Losh 		return (0);
124d626906bSWarner Losh 	}
125d626906bSWarner Losh 	return (args.ebx & 0xffff);
126d626906bSWarner Losh }
127d626906bSWarner Losh 
12812a02d6eSMike Smith /*
12912a02d6eSMike Smith  * Initialise access to PCI configuration space
13012a02d6eSMike Smith  */
13112a02d6eSMike Smith int
13212a02d6eSMike Smith pci_cfgregopen(void)
13321c3015aSDoug Rabson {
13412a02d6eSMike Smith 	static int		opened = 0;
13554c9005fSWarner Losh 	u_long			sigaddr;
13654c9005fSWarner Losh 	static struct PIR_table	*pt;
13754c9005fSWarner Losh 	u_int8_t		ck, *cv;
13854c9005fSWarner Losh 	int			i;
13921c3015aSDoug Rabson 
14012a02d6eSMike Smith 	if (opened)
14112a02d6eSMike Smith 		return(1);
142300451c4SMike Smith 
143e300f53cSWarner Losh 	if (pcibios_cfgopen() != 0)
144300451c4SMike Smith 		usebios = 1;
145e300f53cSWarner Losh 	else if (pcireg_cfgopen() != 0)
146300451c4SMike Smith 		usebios = 0;
147e300f53cSWarner Losh 	else
148300451c4SMike Smith 		return(0);
14954c9005fSWarner Losh 
15054c9005fSWarner Losh 	/*
15154c9005fSWarner Losh 	 * Look for the interrupt routing table.
152a8c18609SWarner Losh 	 *
153a8c18609SWarner Losh 	 * We use PCI BIOS's PIR table if it's available $PIR is the
154a8c18609SWarner Losh 	 * standard way to do this.  Sadly, some machines are not
155a8c18609SWarner Losh 	 * standards conforming and have _PIR instead.  We shrug and cope
156a8c18609SWarner Losh 	 * by looking for both.
15754c9005fSWarner Losh 	 */
158a8c18609SWarner Losh 	if (pcibios_get_version() >= 0x0210 && pt == NULL) {
159a8c18609SWarner Losh 		sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0);
160a8c18609SWarner Losh 		if (sigaddr == 0)
161a8c18609SWarner Losh 			sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
162a8c18609SWarner Losh 		if (sigaddr != 0) {
163e300f53cSWarner Losh 			pt = (struct PIR_table *)(uintptr_t)
164e300f53cSWarner Losh 			    BIOS_PADDRTOVADDR(sigaddr);
165a8c18609SWarner Losh 			for (cv = (u_int8_t *)pt, ck = 0, i = 0;
166a8c18609SWarner Losh 			     i < (pt->pt_header.ph_length); i++) {
16754c9005fSWarner Losh 				ck += cv[i];
16854c9005fSWarner Losh 			}
16954c9005fSWarner Losh 			if (ck == 0) {
170099d058bSMike Smith 				pci_route_table = pt;
171a8c18609SWarner Losh 				pci_route_count = (pt->pt_header.ph_length -
172e300f53cSWarner Losh 				    sizeof(struct PIR_header)) /
173e300f53cSWarner Losh 				    sizeof(struct PIR_entry);
174a8c18609SWarner Losh 				printf("Using $PIR table, %d entries at %p\n",
175a8c18609SWarner Losh 				    pci_route_count, pci_route_table);
17654c9005fSWarner Losh 			}
17754c9005fSWarner Losh 		}
178a8c18609SWarner Losh 	}
17912a02d6eSMike Smith 	opened = 1;
180300451c4SMike Smith 	return(1);
181300451c4SMike Smith }
182300451c4SMike Smith 
18312a02d6eSMike Smith /*
18412a02d6eSMike Smith  * Read configuration space register
18512a02d6eSMike Smith  */
18647c6b726SPeter Wemm static u_int32_t
187bb0d0a8eSMike Smith pci_do_cfgregread(int bus, int slot, int func, int reg, int bytes)
18812a02d6eSMike Smith {
18912a02d6eSMike Smith 	return(usebios ?
19012a02d6eSMike Smith 	    pcibios_cfgread(bus, slot, func, reg, bytes) :
19112a02d6eSMike Smith 	    pcireg_cfgread(bus, slot, func, reg, bytes));
19212a02d6eSMike Smith }
193300451c4SMike Smith 
194bb0d0a8eSMike Smith u_int32_t
195bb0d0a8eSMike Smith pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
196bb0d0a8eSMike Smith {
197e300f53cSWarner Losh 	uint32_t line;
198bb0d0a8eSMike Smith #ifdef APIC_IO
199e300f53cSWarner Losh 	uint32_t pin;
200e300f53cSWarner Losh 
201bb0d0a8eSMike Smith 	/*
202e300f53cSWarner Losh 	 * If we are using the APIC, the contents of the intline
203e300f53cSWarner Losh 	 * register will probably be wrong (since they are set up for
204e300f53cSWarner Losh 	 * use with the PIC.  Rather than rewrite these registers
205e300f53cSWarner Losh 	 * (maybe that would be smarter) we trap attempts to read them
206e300f53cSWarner Losh 	 * and translate to our private vector numbers.
207bb0d0a8eSMike Smith 	 */
208bb0d0a8eSMike Smith 	if ((reg == PCIR_INTLINE) && (bytes == 1)) {
209bb0d0a8eSMike Smith 
210bb0d0a8eSMike Smith 		pin = pci_do_cfgregread(bus, slot, func, PCIR_INTPIN, 1);
211bb0d0a8eSMike Smith 		line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1);
212bb0d0a8eSMike Smith 
213bb0d0a8eSMike Smith 		if (pin != 0) {
214bb0d0a8eSMike Smith 			int airq;
215bb0d0a8eSMike Smith 
216bb0d0a8eSMike Smith 			airq = pci_apic_irq(bus, slot, pin);
217bb0d0a8eSMike Smith 			if (airq >= 0) {
218bb0d0a8eSMike Smith 				/* PCI specific entry found in MP table */
219bb0d0a8eSMike Smith 				if (airq != line)
220bb0d0a8eSMike Smith 					undirect_pci_irq(line);
221bb0d0a8eSMike Smith 				return(airq);
222bb0d0a8eSMike Smith 			} else {
223bb0d0a8eSMike Smith 				/*
224e300f53cSWarner Losh 				 * PCI interrupts might be redirected
225e300f53cSWarner Losh 				 * to the ISA bus according to some MP
226e300f53cSWarner Losh 				 * tables. Use the same methods as
227e300f53cSWarner Losh 				 * used by the ISA devices devices to
228e300f53cSWarner Losh 				 * find the proper IOAPIC int pin.
229bb0d0a8eSMike Smith 				 */
230bb0d0a8eSMike Smith 				airq = isa_apic_irq(line);
231bb0d0a8eSMike Smith 				if ((airq >= 0) && (airq != line)) {
232bb0d0a8eSMike Smith 					/* XXX: undirect_pci_irq() ? */
233bb0d0a8eSMike Smith 					undirect_isa_irq(line);
234bb0d0a8eSMike Smith 					return(airq);
235bb0d0a8eSMike Smith 				}
236bb0d0a8eSMike Smith 			}
237bb0d0a8eSMike Smith 		}
238bb0d0a8eSMike Smith 		return(line);
239bb0d0a8eSMike Smith 	}
240d5ccecfaSWarner Losh #else
241d5ccecfaSWarner Losh 	/*
242d5ccecfaSWarner Losh 	 * Some BIOS writers seem to want to ignore the spec and put
243d5ccecfaSWarner Losh 	 * 0 in the intline rather than 255 to indicate none.  The rest of
244d5ccecfaSWarner Losh 	 * the code uses 255 as an invalid IRQ.
245d5ccecfaSWarner Losh 	 */
246d5ccecfaSWarner Losh 	if (reg == PCIR_INTLINE && bytes == 1) {
247d5ccecfaSWarner Losh 		line = pci_do_cfgregread(bus, slot, func, PCIR_INTLINE, 1);
2488ce1ab3aSWarner Losh 		return pci_i386_map_intline(line);
249d5ccecfaSWarner Losh 	}
250bb0d0a8eSMike Smith #endif /* APIC_IO */
251bb0d0a8eSMike Smith 	return(pci_do_cfgregread(bus, slot, func, reg, bytes));
252bb0d0a8eSMike Smith }
253bb0d0a8eSMike Smith 
25412a02d6eSMike Smith /*
25512a02d6eSMike Smith  * Write configuration space register
25612a02d6eSMike Smith  */
25712a02d6eSMike Smith void
25812a02d6eSMike Smith pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
25912a02d6eSMike Smith {
26012a02d6eSMike Smith     return (usebios ?
26112a02d6eSMike Smith 	pcibios_cfgwrite(bus, slot, func, reg, data, bytes) :
26212a02d6eSMike Smith 	pcireg_cfgwrite(bus, slot, func, reg, data, bytes));
26312a02d6eSMike Smith }
26412a02d6eSMike Smith 
26512a02d6eSMike Smith /*
26654c9005fSWarner Losh  * Route a PCI interrupt
26754c9005fSWarner Losh  *
2689d558634SMike Smith  * XXX we don't do anything "right" with the function number in the PIR table
269099d058bSMike Smith  *     (because the consumer isn't currently passing it in).  We don't care
270099d058bSMike Smith  *     anyway, due to the way PCI interrupts are assigned.
27154c9005fSWarner Losh  */
27254c9005fSWarner Losh int
27354c9005fSWarner Losh pci_cfgintr(int bus, int device, int pin)
27454c9005fSWarner Losh {
27554c9005fSWarner Losh 	struct PIR_entry	*pe;
2769d558634SMike Smith 	int			i, irq;
2779d558634SMike Smith 	struct bios_regs	args;
278d626906bSWarner Losh 	u_int16_t		v;
279d3b6477aSWarner Losh 	int already = 0;
28054c9005fSWarner Losh 
281d626906bSWarner Losh 	v = pcibios_get_version();
282d626906bSWarner Losh 	if (v < 0x0210) {
283d626906bSWarner Losh 		PRVERB((
284d626906bSWarner Losh 		"pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n",
285d626906bSWarner Losh 		    (v & 0xff00) >> 8, v & 0xff));
286e300f53cSWarner Losh 		return (PCI_INVALID_IRQ);
287d626906bSWarner Losh 	}
288a3793252SWarner Losh 	if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
289a3793252SWarner Losh 	    (pin < 1) || (pin > 4))
290e300f53cSWarner Losh 		return(PCI_INVALID_IRQ);
29154c9005fSWarner Losh 
29254c9005fSWarner Losh 	/*
29354c9005fSWarner Losh 	 * Scan the entry table for a contender
29454c9005fSWarner Losh 	 */
295e300f53cSWarner Losh 	for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count;
296e300f53cSWarner Losh 	     i++, pe++) {
29754c9005fSWarner Losh 		if ((bus != pe->pe_bus) || (device != pe->pe_device))
29854c9005fSWarner Losh 			continue;
299099d058bSMike Smith 
300099d058bSMike Smith 		irq = pci_cfgintr_linked(pe, pin);
301e300f53cSWarner Losh 		if (irq == PCI_INVALID_IRQ)
302d626906bSWarner Losh 			irq = pci_cfgintr_unique(pe, pin);
303e300f53cSWarner Losh 		if (irq != PCI_INVALID_IRQ)
304654d58caSWarner Losh 			already = 1;
305e300f53cSWarner Losh 		if (irq == PCI_INVALID_IRQ)
306099d058bSMike Smith 			irq = pci_cfgintr_virgin(pe, pin);
307e300f53cSWarner Losh 		if (irq == PCI_INVALID_IRQ)
30854c9005fSWarner Losh 			break;
309099d058bSMike Smith 
3109d558634SMike Smith 		/*
3119d558634SMike Smith 		 * Ask the BIOS to route the interrupt
3129d558634SMike Smith 		 */
3139d558634SMike Smith 		args.eax = PCIBIOS_ROUTE_INTERRUPT;
3149d558634SMike Smith 		args.ebx = (bus << 8) | (device << 3);
315e300f53cSWarner Losh 		/* pin value is 0xa - 0xd */
316e300f53cSWarner Losh 		args.ecx = (irq << 8) | (0xa + pin - 1);
317e300f53cSWarner Losh 		if (!already &&
318e300f53cSWarner Losh 		    bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
319d626906bSWarner Losh 			/*
320d626906bSWarner Losh 			 * XXX if it fails, we should try to smack the router
321d626906bSWarner Losh 			 * hardware directly.
322e300f53cSWarner Losh 			 * XXX Also, there may be other choices that we can
323e300f53cSWarner Losh 			 * try that will work.
324d626906bSWarner Losh 			 */
325d3b6477aSWarner Losh 			PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n"));
326e300f53cSWarner Losh 			return(PCI_INVALID_IRQ);
327d626906bSWarner Losh 		}
328e300f53cSWarner Losh 		printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus,
329e300f53cSWarner Losh 		    device, 'A' + pin - 1, irq);
3309d558634SMike Smith 		return(irq);
33154c9005fSWarner Losh 	}
332099d058bSMike Smith 
333e300f53cSWarner Losh 	PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus,
334e300f53cSWarner Losh 	    device, 'A' + pin - 1));
335e300f53cSWarner Losh 	return(PCI_INVALID_IRQ);
336099d058bSMike Smith }
337099d058bSMike Smith 
338099d058bSMike Smith /*
339099d058bSMike Smith  * Look to see if the routing table claims this pin is uniquely routed.
340099d058bSMike Smith  */
341099d058bSMike Smith static int
342099d058bSMike Smith pci_cfgintr_unique(struct PIR_entry *pe, int pin)
343099d058bSMike Smith {
344099d058bSMike Smith 	int		irq;
345d5ccecfaSWarner Losh 	uint32_t	irqmask;
346099d058bSMike Smith 
347d5ccecfaSWarner Losh 	irqmask = pe->pe_intpin[pin - 1].irqs;
348d5ccecfaSWarner Losh 	if (irqmask != 0 && powerof2(irqmask)) {
349d5ccecfaSWarner Losh 		irq = ffs(irqmask) - 1;
350d626906bSWarner Losh 		PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq));
351099d058bSMike Smith 		return(irq);
352099d058bSMike Smith 	}
353e300f53cSWarner Losh 	return(PCI_INVALID_IRQ);
354099d058bSMike Smith }
355099d058bSMike Smith 
356099d058bSMike Smith /*
357099d058bSMike Smith  * Look for another device which shares the same link byte and
358099d058bSMike Smith  * already has a unique IRQ, or which has had one routed already.
359099d058bSMike Smith  */
360099d058bSMike Smith static int
361099d058bSMike Smith pci_cfgintr_linked(struct PIR_entry *pe, int pin)
362099d058bSMike Smith {
363099d058bSMike Smith 	struct PIR_entry	*oe;
364099d058bSMike Smith 	struct PIR_intpin	*pi;
365099d058bSMike Smith 	int			i, j, irq;
366099d058bSMike Smith 
367099d058bSMike Smith 	/*
368099d058bSMike Smith 	 * Scan table slots.
369099d058bSMike Smith 	 */
370e300f53cSWarner Losh 	for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count;
371e300f53cSWarner Losh 	     i++, oe++) {
372099d058bSMike Smith 		/* scan interrupt pins */
373099d058bSMike Smith 		for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
374099d058bSMike Smith 
375e300f53cSWarner Losh 			/* don't look at the entry we're trying to match */
376099d058bSMike Smith 			if ((pe == oe) && (i == (pin - 1)))
377099d058bSMike Smith 				continue;
378099d058bSMike Smith 			/* compare link bytes */
379099d058bSMike Smith 			if (pi->link != pe->pe_intpin[pin - 1].link)
380099d058bSMike Smith 				continue;
381099d058bSMike Smith 			/* link destination mapped to a unique interrupt? */
382d5ccecfaSWarner Losh 			if (pi->irqs != 0 && powerof2(pi->irqs)) {
383099d058bSMike Smith 				irq = ffs(pi->irqs) - 1;
384d626906bSWarner Losh 				PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
385d626906bSWarner Losh 				    pi->link, irq));
386099d058bSMike Smith 				return(irq);
387099d058bSMike Smith 			}
388099d058bSMike Smith 
389e300f53cSWarner Losh 			/*
390e300f53cSWarner Losh 			 * look for the real PCI device that matches this
391e300f53cSWarner Losh 			 * table entry
392e300f53cSWarner Losh 			 */
393e300f53cSWarner Losh 			irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device,
394e300f53cSWarner Losh 			    j, pin);
395e300f53cSWarner Losh 			if (irq != PCI_INVALID_IRQ)
396099d058bSMike Smith 				return(irq);
397099d058bSMike Smith 		}
398099d058bSMike Smith 	}
399e300f53cSWarner Losh 	return(PCI_INVALID_IRQ);
400099d058bSMike Smith }
401099d058bSMike Smith 
402099d058bSMike Smith /*
403099d058bSMike Smith  * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
404099d058bSMike Smith  * see if it has already been assigned an interrupt.
405099d058bSMike Smith  */
406099d058bSMike Smith static int
407099d058bSMike Smith pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
408099d058bSMike Smith {
409099d058bSMike Smith 	devclass_t		pci_devclass;
410099d058bSMike Smith 	device_t		*pci_devices;
411099d058bSMike Smith 	int			pci_count;
412099d058bSMike Smith 	device_t		*pci_children;
413099d058bSMike Smith 	int			pci_childcount;
414099d058bSMike Smith 	device_t		*busp, *childp;
415099d058bSMike Smith 	int			i, j, irq;
416099d058bSMike Smith 
417099d058bSMike Smith 	/*
418099d058bSMike Smith 	 * Find all the PCI busses.
419099d058bSMike Smith 	 */
420099d058bSMike Smith 	pci_count = 0;
421099d058bSMike Smith 	if ((pci_devclass = devclass_find("pci")) != NULL)
422099d058bSMike Smith 		devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
423099d058bSMike Smith 
424099d058bSMike Smith 	/*
425099d058bSMike Smith 	 * Scan all the PCI busses/devices looking for this one.
426099d058bSMike Smith 	 */
427e300f53cSWarner Losh 	irq = PCI_INVALID_IRQ;
428e300f53cSWarner Losh 	for (i = 0, busp = pci_devices; (i < pci_count) && (irq == PCI_INVALID_IRQ);
429e300f53cSWarner Losh 	     i++, busp++) {
430099d058bSMike Smith 		pci_childcount = 0;
431099d058bSMike Smith 		device_get_children(*busp, &pci_children, &pci_childcount);
432099d058bSMike Smith 
433e300f53cSWarner Losh 		for (j = 0, childp = pci_children; j < pci_childcount; j++,
434e300f53cSWarner Losh 		    childp++) {
435099d058bSMike Smith 			if ((pci_get_bus(*childp) == bus) &&
436099d058bSMike Smith 			    (pci_get_slot(*childp) == device) &&
4371cf5f555SWarner Losh 			    (pci_get_intpin(*childp) == matchpin)) {
4388ce1ab3aSWarner Losh 				irq = pci_i386_map_intline(pci_get_irq(*childp));
439e300f53cSWarner Losh 				if (irq != PCI_INVALID_IRQ)
440d626906bSWarner Losh 					PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
44185fab963SMike Smith 					    pe->pe_intpin[pin - 1].link, irq,
442e300f53cSWarner Losh 					    pci_get_bus(*childp),
443e300f53cSWarner Losh 					    pci_get_slot(*childp),
444e300f53cSWarner Losh 					    pci_get_function(*childp)));
4456c9eb5f3SMike Smith 				break;
4466c9eb5f3SMike Smith 			}
4476c9eb5f3SMike Smith 		}
4486c9eb5f3SMike Smith 		if (pci_children != NULL)
4496c9eb5f3SMike Smith 			free(pci_children, M_TEMP);
4506c9eb5f3SMike Smith 	}
4516c9eb5f3SMike Smith 	if (pci_devices != NULL)
4526c9eb5f3SMike Smith 		free(pci_devices, M_TEMP);
453099d058bSMike Smith 	return(irq);
454099d058bSMike Smith }
455099d058bSMike Smith 
456099d058bSMike Smith /*
457099d058bSMike Smith  * Pick a suitable IRQ from those listed as routable to this device.
458099d058bSMike Smith  */
459099d058bSMike Smith static int
460099d058bSMike Smith pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
461099d058bSMike Smith {
462099d058bSMike Smith 	int		irq, ibit;
463099d058bSMike Smith 
464e300f53cSWarner Losh 	/*
465e300f53cSWarner Losh 	 * first scan the set of PCI-only interrupts and see if any of these
466e300f53cSWarner Losh 	 * are routable
467e300f53cSWarner Losh 	 */
468099d058bSMike Smith 	for (irq = 0; irq < 16; irq++) {
469099d058bSMike Smith 		ibit = (1 << irq);
470099d058bSMike Smith 
471099d058bSMike Smith 		/* can we use this interrupt? */
472099d058bSMike Smith 		if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
473099d058bSMike Smith 		    (pe->pe_intpin[pin - 1].irqs & ibit)) {
474d626906bSWarner Losh 			PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq));
475099d058bSMike Smith 			return(irq);
476099d058bSMike Smith 		}
477099d058bSMike Smith 	}
478099d058bSMike Smith 
479099d058bSMike Smith 	/* life is tough, so just pick an interrupt */
480099d058bSMike Smith 	for (irq = 0; irq < 16; irq++) {
481099d058bSMike Smith 		ibit = (1 << irq);
482099d058bSMike Smith 		if (pe->pe_intpin[pin - 1].irqs & ibit) {
483d626906bSWarner Losh 			PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq));
484099d058bSMike Smith 			return(irq);
485099d058bSMike Smith 		}
486099d058bSMike Smith 	}
487e300f53cSWarner Losh 	return(PCI_INVALID_IRQ);
48854c9005fSWarner Losh }
48954c9005fSWarner Losh 
49054c9005fSWarner Losh 
49154c9005fSWarner Losh /*
49212a02d6eSMike Smith  * Config space access using BIOS functions
49312a02d6eSMike Smith  */
494300451c4SMike Smith static int
49521c3015aSDoug Rabson pcibios_cfgread(int bus, int slot, int func, int reg, int bytes)
496300451c4SMike Smith {
497300451c4SMike Smith 	struct bios_regs args;
498ac9b3dacSMike Smith 	u_int mask;
499300451c4SMike Smith 
500300451c4SMike Smith 	switch(bytes) {
501300451c4SMike Smith 	case 1:
502300451c4SMike Smith 		args.eax = PCIBIOS_READ_CONFIG_BYTE;
503ac9b3dacSMike Smith 		mask = 0xff;
504300451c4SMike Smith 		break;
505300451c4SMike Smith 	case 2:
506300451c4SMike Smith 		args.eax = PCIBIOS_READ_CONFIG_WORD;
507ac9b3dacSMike Smith 		mask = 0xffff;
508300451c4SMike Smith 		break;
509300451c4SMike Smith 	case 4:
510300451c4SMike Smith 		args.eax = PCIBIOS_READ_CONFIG_DWORD;
511ac9b3dacSMike Smith 		mask = 0xffffffff;
512300451c4SMike Smith 		break;
513300451c4SMike Smith 	default:
514300451c4SMike Smith 		return(-1);
515300451c4SMike Smith 	}
51621c3015aSDoug Rabson 	args.ebx = (bus << 8) | (slot << 3) | func;
517300451c4SMike Smith 	args.edi = reg;
518300451c4SMike Smith 	bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
519300451c4SMike Smith 	/* check call results? */
520ac9b3dacSMike Smith 	return(args.ecx & mask);
521300451c4SMike Smith }
522300451c4SMike Smith 
523300451c4SMike Smith static void
52421c3015aSDoug Rabson pcibios_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
525300451c4SMike Smith {
526300451c4SMike Smith 	struct bios_regs args;
527300451c4SMike Smith 
528300451c4SMike Smith 	switch(bytes) {
529300451c4SMike Smith 	case 1:
530300451c4SMike Smith 		args.eax = PCIBIOS_WRITE_CONFIG_BYTE;
531300451c4SMike Smith 		break;
532300451c4SMike Smith 	case 2:
533300451c4SMike Smith 		args.eax = PCIBIOS_WRITE_CONFIG_WORD;
534300451c4SMike Smith 		break;
535300451c4SMike Smith 	case 4:
536300451c4SMike Smith 		args.eax = PCIBIOS_WRITE_CONFIG_DWORD;
537300451c4SMike Smith 		break;
538300451c4SMike Smith 	default:
539300451c4SMike Smith 		return;
540300451c4SMike Smith 	}
54121c3015aSDoug Rabson 	args.ebx = (bus << 8) | (slot << 3) | func;
542300451c4SMike Smith 	args.ecx = data;
543300451c4SMike Smith 	args.edi = reg;
544300451c4SMike Smith 	bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL));
545300451c4SMike Smith }
546300451c4SMike Smith 
54712a02d6eSMike Smith /*
54812a02d6eSMike Smith  * Determine whether there is a PCI BIOS present
54912a02d6eSMike Smith  */
550300451c4SMike Smith static int
551300451c4SMike Smith pcibios_cfgopen(void)
552300451c4SMike Smith {
5530b9427deSWarner Losh 	u_int16_t		v = 0;
5540b9427deSWarner Losh 
5555264a94fSJohn Baldwin 	if (PCIbios.ventry != 0 && enable_pcibios) {
5560b9427deSWarner Losh 		v = pcibios_get_version();
5570b9427deSWarner Losh 		if (v > 0)
558e300f53cSWarner Losh 			printf("pcibios: BIOS version %x.%02x\n",
559e300f53cSWarner Losh 			    (v & 0xff00) >> 8, v & 0xff);
5600b9427deSWarner Losh 	}
5610b9427deSWarner Losh 	return (v > 0);
562300451c4SMike Smith }
563300451c4SMike Smith 
56412a02d6eSMike Smith /*
56512a02d6eSMike Smith  * Configuration space access using direct register operations
56612a02d6eSMike Smith  */
567ac19f918SStefan Eßer 
5685bec6157SStefan Eßer /* enable configuration space accesses and return data port address */
569a3adc4f8SStefan Eßer static int
5705bec6157SStefan Eßer pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
5715bec6157SStefan Eßer {
5725bec6157SStefan Eßer 	int dataport = 0;
5735bec6157SStefan Eßer 
5745bec6157SStefan Eßer 	if (bus <= PCI_BUSMAX
5755bec6157SStefan Eßer 	    && slot < devmax
5765bec6157SStefan Eßer 	    && func <= PCI_FUNCMAX
5775bec6157SStefan Eßer 	    && reg <= PCI_REGMAX
5785bec6157SStefan Eßer 	    && bytes != 3
5795bec6157SStefan Eßer 	    && (unsigned) bytes <= 4
5805bec6157SStefan Eßer 	    && (reg & (bytes -1)) == 0) {
5815bec6157SStefan Eßer 		switch (cfgmech) {
5825bec6157SStefan Eßer 		case 1:
583b3daa02eSStefan Eßer 			outl(CONF1_ADDR_PORT, (1 << 31)
584b3daa02eSStefan Eßer 			    | (bus << 16) | (slot << 11)
585b3daa02eSStefan Eßer 			    | (func << 8) | (reg & ~0x03));
586b3daa02eSStefan Eßer 			dataport = CONF1_DATA_PORT + (reg & 0x03);
5875bec6157SStefan Eßer 			break;
5885bec6157SStefan Eßer 		case 2:
5895bec6157SStefan Eßer 			outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
5905bec6157SStefan Eßer 			outb(CONF2_FORWARD_PORT, bus);
5915bec6157SStefan Eßer 			dataport = 0xc000 | (slot << 8) | reg;
5925bec6157SStefan Eßer 			break;
5935bec6157SStefan Eßer 		}
5945bec6157SStefan Eßer 	}
5955bec6157SStefan Eßer 	return (dataport);
5965bec6157SStefan Eßer }
5975bec6157SStefan Eßer 
5985bec6157SStefan Eßer /* disable configuration space accesses */
5995bec6157SStefan Eßer static void
6005bec6157SStefan Eßer pci_cfgdisable(void)
6015bec6157SStefan Eßer {
6025bec6157SStefan Eßer 	switch (cfgmech) {
6035bec6157SStefan Eßer 	case 1:
6045bec6157SStefan Eßer 		outl(CONF1_ADDR_PORT, 0);
6055bec6157SStefan Eßer 		break;
6065bec6157SStefan Eßer 	case 2:
6075bec6157SStefan Eßer 		outb(CONF2_ENABLE_PORT, 0);
6085bec6157SStefan Eßer 		outb(CONF2_FORWARD_PORT, 0);
6095bec6157SStefan Eßer 		break;
6105bec6157SStefan Eßer 	}
6115bec6157SStefan Eßer }
6125bec6157SStefan Eßer 
613300451c4SMike Smith static int
61421c3015aSDoug Rabson pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
6155bec6157SStefan Eßer {
6165bec6157SStefan Eßer 	int data = -1;
6175bec6157SStefan Eßer 	int port;
6185bec6157SStefan Eßer 
61921c3015aSDoug Rabson 	port = pci_cfgenable(bus, slot, func, reg, bytes);
6205bec6157SStefan Eßer 
6215bec6157SStefan Eßer 	if (port != 0) {
6225bec6157SStefan Eßer 		switch (bytes) {
6235bec6157SStefan Eßer 		case 1:
6245bec6157SStefan Eßer 			data = inb(port);
6255bec6157SStefan Eßer 			break;
6265bec6157SStefan Eßer 		case 2:
6275bec6157SStefan Eßer 			data = inw(port);
6285bec6157SStefan Eßer 			break;
6295bec6157SStefan Eßer 		case 4:
6305bec6157SStefan Eßer 			data = inl(port);
6315bec6157SStefan Eßer 			break;
6325bec6157SStefan Eßer 		}
6335bec6157SStefan Eßer 		pci_cfgdisable();
6345bec6157SStefan Eßer 	}
6355bec6157SStefan Eßer 	return (data);
6365bec6157SStefan Eßer }
6375bec6157SStefan Eßer 
638300451c4SMike Smith static void
63921c3015aSDoug Rabson pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
6405bec6157SStefan Eßer {
6415bec6157SStefan Eßer 	int port;
6425bec6157SStefan Eßer 
64321c3015aSDoug Rabson 	port = pci_cfgenable(bus, slot, func, reg, bytes);
6445bec6157SStefan Eßer 	if (port != 0) {
6455bec6157SStefan Eßer 		switch (bytes) {
6465bec6157SStefan Eßer 		case 1:
6475bec6157SStefan Eßer 			outb(port, data);
6485bec6157SStefan Eßer 			break;
6495bec6157SStefan Eßer 		case 2:
6505bec6157SStefan Eßer 			outw(port, data);
6515bec6157SStefan Eßer 			break;
6525bec6157SStefan Eßer 		case 4:
6535bec6157SStefan Eßer 			outl(port, data);
6545bec6157SStefan Eßer 			break;
6555bec6157SStefan Eßer 		}
6565bec6157SStefan Eßer 		pci_cfgdisable();
6575bec6157SStefan Eßer 	}
6585bec6157SStefan Eßer }
6595bec6157SStefan Eßer 
66012a02d6eSMike Smith /* check whether the configuration mechanism has been correctly identified */
6615bec6157SStefan Eßer static int
6625bec6157SStefan Eßer pci_cfgcheck(int maxdev)
663a3adc4f8SStefan Eßer {
664a3adc4f8SStefan Eßer 	u_char device;
665a3adc4f8SStefan Eßer 
6665bec6157SStefan Eßer 	if (bootverbose)
6675bec6157SStefan Eßer 		printf("pci_cfgcheck:\tdevice ");
66877b57314SStefan Eßer 
6695bec6157SStefan Eßer 	for (device = 0; device < maxdev; device++) {
6705bec6157SStefan Eßer 		unsigned id, class, header;
671c7483249SStefan Eßer 		if (bootverbose)
672c7483249SStefan Eßer 			printf("%d ", device);
6735bec6157SStefan Eßer 
6745bec6157SStefan Eßer 		id = inl(pci_cfgenable(0, device, 0, 0, 4));
6755bec6157SStefan Eßer 		if (id == 0 || id == -1)
67681cf5d7aSStefan Eßer 			continue;
67781cf5d7aSStefan Eßer 
6785bec6157SStefan Eßer 		class = inl(pci_cfgenable(0, device, 0, 8, 4)) >> 8;
67981cf5d7aSStefan Eßer 		if (bootverbose)
6805bec6157SStefan Eßer 			printf("[class=%06x] ", class);
6818277ac25SStefan Eßer 		if (class == 0 || (class & 0xf870ff) != 0)
68281cf5d7aSStefan Eßer 			continue;
68381cf5d7aSStefan Eßer 
6845bec6157SStefan Eßer 		header = inb(pci_cfgenable(0, device, 0, 14, 1));
68581cf5d7aSStefan Eßer 		if (bootverbose)
6865bec6157SStefan Eßer 			printf("[hdr=%02x] ", header);
6875bec6157SStefan Eßer 		if ((header & 0x7e) != 0)
68881cf5d7aSStefan Eßer 			continue;
68981cf5d7aSStefan Eßer 
6905bec6157SStefan Eßer 		if (bootverbose)
6915bec6157SStefan Eßer 			printf("is there (id=%08x)\n", id);
6925bec6157SStefan Eßer 
6935bec6157SStefan Eßer 		pci_cfgdisable();
6945bec6157SStefan Eßer 		return (1);
695a3adc4f8SStefan Eßer 	}
696c7483249SStefan Eßer 	if (bootverbose)
697c7483249SStefan Eßer 		printf("-- nothing found\n");
6985bec6157SStefan Eßer 
6995bec6157SStefan Eßer 	pci_cfgdisable();
7005bec6157SStefan Eßer 	return (0);
701a3adc4f8SStefan Eßer }
702d7ea35fcSStefan Eßer 
7038dc26439SPeter Wemm static int
704300451c4SMike Smith pcireg_cfgopen(void)
705ac19f918SStefan Eßer {
706287911bdSStefan Eßer 	unsigned long mode1res,oldval1;
707287911bdSStefan Eßer 	unsigned char mode2res,oldval2;
7080847c06dSStefan Eßer 
709287911bdSStefan Eßer 	oldval1 = inl(CONF1_ADDR_PORT);
710a3adc4f8SStefan Eßer 
71177b57314SStefan Eßer 	if (bootverbose) {
7125bec6157SStefan Eßer 		printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08lx\n",
7135bec6157SStefan Eßer 		    oldval1);
714a3adc4f8SStefan Eßer 	}
715a3adc4f8SStefan Eßer 
7160e2f699bSStefan Eßer 	if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
717287911bdSStefan Eßer 
7185bec6157SStefan Eßer 		cfgmech = 1;
7195bec6157SStefan Eßer 		devmax = 32;
72077b57314SStefan Eßer 
72177b57314SStefan Eßer 		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
72277b57314SStefan Eßer 		outb(CONF1_ADDR_PORT +3, 0);
72377b57314SStefan Eßer 		mode1res = inl(CONF1_ADDR_PORT);
724287911bdSStefan Eßer 		outl(CONF1_ADDR_PORT, oldval1);
72577b57314SStefan Eßer 
72677b57314SStefan Eßer 		if (bootverbose)
7275bec6157SStefan Eßer 			printf("pci_open(1a):\tmode1res=0x%08lx (0x%08lx)\n",
72877b57314SStefan Eßer 			    mode1res, CONF1_ENABLE_CHK);
72977b57314SStefan Eßer 
73077b57314SStefan Eßer 		if (mode1res) {
7315bec6157SStefan Eßer 			if (pci_cfgcheck(32))
7325bec6157SStefan Eßer 				return (cfgmech);
7335bec6157SStefan Eßer 		}
73477b57314SStefan Eßer 
73577b57314SStefan Eßer 		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
73677b57314SStefan Eßer 		mode1res = inl(CONF1_ADDR_PORT);
737287911bdSStefan Eßer 		outl(CONF1_ADDR_PORT, oldval1);
73877b57314SStefan Eßer 
73977b57314SStefan Eßer 		if (bootverbose)
7405bec6157SStefan Eßer 			printf("pci_open(1b):\tmode1res=0x%08lx (0x%08lx)\n",
74177b57314SStefan Eßer 			    mode1res, CONF1_ENABLE_CHK1);
74277b57314SStefan Eßer 
743c7483249SStefan Eßer 		if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
7445bec6157SStefan Eßer 			if (pci_cfgcheck(32))
7455bec6157SStefan Eßer 				return (cfgmech);
746287911bdSStefan Eßer 		}
7475bec6157SStefan Eßer 	}
74877b57314SStefan Eßer 
749287911bdSStefan Eßer 	oldval2 = inb(CONF2_ENABLE_PORT);
750287911bdSStefan Eßer 
751287911bdSStefan Eßer 	if (bootverbose) {
7525bec6157SStefan Eßer 		printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
7535bec6157SStefan Eßer 		    oldval2);
754287911bdSStefan Eßer 	}
755287911bdSStefan Eßer 
756287911bdSStefan Eßer 	if ((oldval2 & 0xf0) == 0) {
757c7483249SStefan Eßer 
7585bec6157SStefan Eßer 		cfgmech = 2;
7595bec6157SStefan Eßer 		devmax = 16;
76077b57314SStefan Eßer 
761287911bdSStefan Eßer 		outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
762287911bdSStefan Eßer 		mode2res = inb(CONF2_ENABLE_PORT);
763287911bdSStefan Eßer 		outb(CONF2_ENABLE_PORT, oldval2);
764287911bdSStefan Eßer 
765287911bdSStefan Eßer 		if (bootverbose)
7665bec6157SStefan Eßer 			printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
767287911bdSStefan Eßer 			    mode2res, CONF2_ENABLE_CHK);
768287911bdSStefan Eßer 
769287911bdSStefan Eßer 		if (mode2res == CONF2_ENABLE_RES) {
770287911bdSStefan Eßer 			if (bootverbose)
7715bec6157SStefan Eßer 				printf("pci_open(2a):\tnow trying mechanism 2\n");
772287911bdSStefan Eßer 
7735bec6157SStefan Eßer 			if (pci_cfgcheck(16))
7745bec6157SStefan Eßer 				return (cfgmech);
775287911bdSStefan Eßer 		}
776287911bdSStefan Eßer 	}
77777b57314SStefan Eßer 
7785bec6157SStefan Eßer 	cfgmech = 0;
7795bec6157SStefan Eßer 	devmax = 0;
7805bec6157SStefan Eßer 	return (cfgmech);
781ac19f918SStefan Eßer }
7828dc26439SPeter Wemm 
783