xref: /freebsd/sys/i386/pci/pci_cfgreg.c (revision 21e25fa60774b9f318b66eadaafb7d450938b72e)
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.
27ac19f918SStefan Eßer  */
28ac19f918SStefan Eßer 
2971c5a901SDavid E. O'Brien #include <sys/cdefs.h>
3071c5a901SDavid E. O'Brien __FBSDID("$FreeBSD$");
3171c5a901SDavid E. O'Brien 
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>
38af3d516fSPeter Wemm #include <sys/lock.h>
39af3d516fSPeter Wemm #include <sys/mutex.h>
40e86bd39aSWarner Losh #include <sys/sysctl.h>
4154c9005fSWarner Losh #include <vm/vm.h>
4254c9005fSWarner Losh #include <vm/pmap.h>
4354c9005fSWarner Losh #include <machine/md_var.h>
44e300f53cSWarner Losh #include <dev/pci/pcivar.h>
45e300f53cSWarner Losh #include <dev/pci/pcireg.h>
462a50a6d7SMike Smith #include <isa/isavar.h>
4712a02d6eSMike Smith #include <machine/pci_cfgreg.h>
48300451c4SMike Smith #include <machine/segments.h>
49300451c4SMike Smith #include <machine/pc/bios.h>
50300451c4SMike Smith 
5121c3015aSDoug Rabson #include "pcib_if.h"
5221c3015aSDoug Rabson 
538ff25e97SJohn Baldwin #define PRVERB(a) do {							\
548ff25e97SJohn Baldwin 	if (bootverbose)						\
558ff25e97SJohn Baldwin 		printf a ;						\
568ff25e97SJohn Baldwin } while(0)
57d626906bSWarner Losh 
585bec6157SStefan Eßer static int cfgmech;
595bec6157SStefan Eßer static int devmax;
60300451c4SMike Smith 
618ab96fd8SJohn Baldwin static int	pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq);
62099d058bSMike Smith static int	pci_cfgintr_unique(struct PIR_entry *pe, int pin);
63099d058bSMike Smith static int	pci_cfgintr_linked(struct PIR_entry *pe, int pin);
64099d058bSMike Smith static int	pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin);
65099d058bSMike Smith static int	pci_cfgintr_virgin(struct PIR_entry *pe, int pin);
66099d058bSMike Smith 
67fbabd7beSJohn Baldwin static void	pci_print_irqmask(u_int16_t irqs);
68fbabd7beSJohn Baldwin static void	pci_print_route_table(struct PIR_table *prt, int size);
6912a02d6eSMike Smith static int	pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
7012a02d6eSMike Smith static void	pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
71300451c4SMike Smith static int	pcireg_cfgopen(void);
72300451c4SMike Smith 
73099d058bSMike Smith static struct PIR_table *pci_route_table;
7454c9005fSWarner Losh static int pci_route_count;
7554c9005fSWarner Losh 
76af3d516fSPeter Wemm static struct mtx pcicfg_mtx;
77af3d516fSPeter Wemm 
78e86bd39aSWarner Losh /* sysctl vars */
79e86bd39aSWarner Losh SYSCTL_DECL(_hw_pci);
80e86bd39aSWarner Losh 
81126ef7fcSYoshihiro Takahashi #ifdef PC98
82126ef7fcSYoshihiro Takahashi #define PCI_IRQ_OVERRIDE_MASK 0x3e68
83126ef7fcSYoshihiro Takahashi #else
84126ef7fcSYoshihiro Takahashi #define PCI_IRQ_OVERRIDE_MASK 0xdef4
85126ef7fcSYoshihiro Takahashi #endif
86126ef7fcSYoshihiro Takahashi 
87126ef7fcSYoshihiro Takahashi static uint32_t pci_irq_override_mask = PCI_IRQ_OVERRIDE_MASK;
88e86bd39aSWarner Losh TUNABLE_INT("hw.pci.irq_override_mask", &pci_irq_override_mask);
89184dcdc7SMike Silbersack SYSCTL_INT(_hw_pci, OID_AUTO, irq_override_mask, CTLFLAG_RDTUN,
90126ef7fcSYoshihiro Takahashi     &pci_irq_override_mask, PCI_IRQ_OVERRIDE_MASK,
91e86bd39aSWarner Losh     "Mask of allowed irqs to try to route when it has no good clue about\n"
92e86bd39aSWarner Losh     "which irqs it should use.");
93e86bd39aSWarner Losh 
94e86bd39aSWarner Losh 
958ce1ab3aSWarner Losh /*
968ce1ab3aSWarner Losh  * Some BIOS writers seem to want to ignore the spec and put
978ce1ab3aSWarner Losh  * 0 in the intline rather than 255 to indicate none.  Some use
988ce1ab3aSWarner Losh  * numbers in the range 128-254 to indicate something strange and
998ce1ab3aSWarner Losh  * apparently undocumented anywhere.  Assume these are completely bogus
1008ce1ab3aSWarner Losh  * and map them to 255, which means "none".
1018ce1ab3aSWarner Losh  */
1028ce1ab3aSWarner Losh static __inline__ int
1038ce1ab3aSWarner Losh pci_i386_map_intline(int line)
1048ce1ab3aSWarner Losh {
1058ce1ab3aSWarner Losh 	if (line == 0 || line >= 128)
106e300f53cSWarner Losh 		return (PCI_INVALID_IRQ);
1078ce1ab3aSWarner Losh 	return (line);
1088ce1ab3aSWarner Losh }
1098ce1ab3aSWarner Losh 
110d626906bSWarner Losh static u_int16_t
111d626906bSWarner Losh pcibios_get_version(void)
112d626906bSWarner Losh {
113d626906bSWarner Losh 	struct bios_regs args;
114d626906bSWarner Losh 
1155264a94fSJohn Baldwin 	if (PCIbios.ventry == 0) {
116d626906bSWarner Losh 		PRVERB(("pcibios: No call entry point\n"));
117d626906bSWarner Losh 		return (0);
118d626906bSWarner Losh 	}
119d626906bSWarner Losh 	args.eax = PCIBIOS_BIOS_PRESENT;
120d626906bSWarner Losh 	if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
121d626906bSWarner Losh 		PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
122d626906bSWarner Losh 		return (0);
123d626906bSWarner Losh 	}
124d626906bSWarner Losh 	if (args.edx != 0x20494350) {
125d626906bSWarner Losh 		PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
126d626906bSWarner Losh 		return (0);
127d626906bSWarner Losh 	}
128d626906bSWarner Losh 	return (args.ebx & 0xffff);
129d626906bSWarner Losh }
130d626906bSWarner Losh 
13112a02d6eSMike Smith /*
13212a02d6eSMike Smith  * Initialise access to PCI configuration space
13312a02d6eSMike Smith  */
13412a02d6eSMike Smith int
13512a02d6eSMike Smith pci_cfgregopen(void)
13621c3015aSDoug Rabson {
13712a02d6eSMike Smith 	static int		opened = 0;
13854c9005fSWarner Losh 	u_long			sigaddr;
13954c9005fSWarner Losh 	static struct PIR_table	*pt;
140af3d516fSPeter Wemm 	u_int16_t		v;
14154c9005fSWarner Losh 	u_int8_t		ck, *cv;
14254c9005fSWarner Losh 	int			i;
14321c3015aSDoug Rabson 
14412a02d6eSMike Smith 	if (opened)
14512a02d6eSMike Smith 		return(1);
146300451c4SMike Smith 
147af3d516fSPeter Wemm 	if (pcireg_cfgopen() == 0)
148300451c4SMike Smith 		return(0);
14954c9005fSWarner Losh 
150af3d516fSPeter Wemm 	v = pcibios_get_version();
151af3d516fSPeter Wemm 	if (v > 0)
152af3d516fSPeter Wemm 		printf("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8,
153af3d516fSPeter Wemm 		    v & 0xff);
154af3d516fSPeter Wemm 
15554c9005fSWarner Losh 	/*
15654c9005fSWarner Losh 	 * Look for the interrupt routing table.
157a8c18609SWarner Losh 	 *
158a8c18609SWarner Losh 	 * We use PCI BIOS's PIR table if it's available $PIR is the
159a8c18609SWarner Losh 	 * standard way to do this.  Sadly, some machines are not
160a8c18609SWarner Losh 	 * standards conforming and have _PIR instead.  We shrug and cope
161a8c18609SWarner Losh 	 * by looking for both.
16254c9005fSWarner Losh 	 */
163a8c18609SWarner Losh 	if (pcibios_get_version() >= 0x0210 && pt == NULL) {
164a8c18609SWarner Losh 		sigaddr = bios_sigsearch(0, "$PIR", 4, 16, 0);
165a8c18609SWarner Losh 		if (sigaddr == 0)
166a8c18609SWarner Losh 			sigaddr = bios_sigsearch(0, "_PIR", 4, 16, 0);
167a8c18609SWarner Losh 		if (sigaddr != 0) {
168e300f53cSWarner Losh 			pt = (struct PIR_table *)(uintptr_t)
169e300f53cSWarner Losh 			    BIOS_PADDRTOVADDR(sigaddr);
170a8c18609SWarner Losh 			for (cv = (u_int8_t *)pt, ck = 0, i = 0;
171a8c18609SWarner Losh 			     i < (pt->pt_header.ph_length); i++) {
17254c9005fSWarner Losh 				ck += cv[i];
17354c9005fSWarner Losh 			}
174fefe985dSJohn Baldwin 			if (ck == 0 && pt->pt_header.ph_length >
175fefe985dSJohn Baldwin 			    sizeof(struct PIR_header)) {
176099d058bSMike Smith 				pci_route_table = pt;
177a8c18609SWarner Losh 				pci_route_count = (pt->pt_header.ph_length -
178e300f53cSWarner Losh 				    sizeof(struct PIR_header)) /
179e300f53cSWarner Losh 				    sizeof(struct PIR_entry);
180a8c18609SWarner Losh 				printf("Using $PIR table, %d entries at %p\n",
181a8c18609SWarner Losh 				    pci_route_count, pci_route_table);
182facfd6e8SJohn Baldwin 				if (bootverbose)
183facfd6e8SJohn Baldwin 					pci_print_route_table(pci_route_table,
184facfd6e8SJohn Baldwin 					    pci_route_count);
18554c9005fSWarner Losh 			}
18654c9005fSWarner Losh 		}
187a8c18609SWarner Losh 	}
188af3d516fSPeter Wemm 	mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
18912a02d6eSMike Smith 	opened = 1;
190300451c4SMike Smith 	return(1);
191300451c4SMike Smith }
192300451c4SMike Smith 
19312a02d6eSMike Smith /*
19412a02d6eSMike Smith  * Read configuration space register
19512a02d6eSMike Smith  */
196bb0d0a8eSMike Smith u_int32_t
197bb0d0a8eSMike Smith pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
198bb0d0a8eSMike Smith {
199e300f53cSWarner Losh 	uint32_t line;
200e300f53cSWarner Losh 
201bb0d0a8eSMike Smith 	/*
202d5ccecfaSWarner Losh 	 * Some BIOS writers seem to want to ignore the spec and put
203d5ccecfaSWarner Losh 	 * 0 in the intline rather than 255 to indicate none.  The rest of
204d5ccecfaSWarner Losh 	 * the code uses 255 as an invalid IRQ.
205d5ccecfaSWarner Losh 	 */
206d5ccecfaSWarner Losh 	if (reg == PCIR_INTLINE && bytes == 1) {
207af3d516fSPeter Wemm 		line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
2086f92bdd0SJohn Baldwin 		return (pci_i386_map_intline(line));
209d5ccecfaSWarner Losh 	}
210af3d516fSPeter Wemm 	return (pcireg_cfgread(bus, slot, func, reg, bytes));
211bb0d0a8eSMike Smith }
212bb0d0a8eSMike Smith 
21312a02d6eSMike Smith /*
21412a02d6eSMike Smith  * Write configuration space register
21512a02d6eSMike Smith  */
21612a02d6eSMike Smith void
21712a02d6eSMike Smith pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
21812a02d6eSMike Smith {
219af3d516fSPeter Wemm 
220cb8e4332SPoul-Henning Kamp 	pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
22112a02d6eSMike Smith }
22212a02d6eSMike Smith 
22312a02d6eSMike Smith /*
22454c9005fSWarner Losh  * Route a PCI interrupt
22554c9005fSWarner Losh  */
22654c9005fSWarner Losh int
2278ab96fd8SJohn Baldwin pci_cfgintr(int bus, int device, int pin, int oldirq)
22854c9005fSWarner Losh {
22954c9005fSWarner Losh 	struct PIR_entry	*pe;
2309d558634SMike Smith 	int			i, irq;
2319d558634SMike Smith 	struct bios_regs	args;
232d626906bSWarner Losh 	u_int16_t		v;
233d3b6477aSWarner Losh  	int already = 0;
234ce494452SWarner Losh  	int errok = 0;
23554c9005fSWarner Losh 
236d626906bSWarner Losh 	v = pcibios_get_version();
237d626906bSWarner Losh 	if (v < 0x0210) {
238d626906bSWarner Losh 		PRVERB((
239d626906bSWarner Losh 		"pci_cfgintr: BIOS %x.%02x doesn't support interrupt routing\n",
240d626906bSWarner Losh 		    (v & 0xff00) >> 8, v & 0xff));
241e300f53cSWarner Losh 		return (PCI_INVALID_IRQ);
242d626906bSWarner Losh 	}
243a3793252SWarner Losh 	if ((bus < 0) || (bus > 255) || (device < 0) || (device > 255) ||
244a3793252SWarner Losh 	    (pin < 1) || (pin > 4))
245e300f53cSWarner Losh 		return(PCI_INVALID_IRQ);
24654c9005fSWarner Losh 
24754c9005fSWarner Losh 	/*
24854c9005fSWarner Losh 	 * Scan the entry table for a contender
24954c9005fSWarner Losh 	 */
250e300f53cSWarner Losh 	for (i = 0, pe = &pci_route_table->pt_entry[0]; i < pci_route_count;
251e300f53cSWarner Losh 	     i++, pe++) {
25254c9005fSWarner Losh 		if ((bus != pe->pe_bus) || (device != pe->pe_device))
25354c9005fSWarner Losh 			continue;
2548ab96fd8SJohn Baldwin 		/*
2558ab96fd8SJohn Baldwin 		 * A link of 0 means that this intpin is not connected to
2568ab96fd8SJohn Baldwin 		 * any other device's interrupt pins and is not connected to
2578ab96fd8SJohn Baldwin 		 * any of the Interrupt Router's interrupt pins, so we can't
2588ab96fd8SJohn Baldwin 		 * route it.
2598ab96fd8SJohn Baldwin 		 */
2608ab96fd8SJohn Baldwin 		if (pe->pe_intpin[pin - 1].link == 0)
2618ab96fd8SJohn Baldwin 			continue;
262099d058bSMike Smith 
2638ab96fd8SJohn Baldwin 		if (pci_cfgintr_valid(pe, pin, oldirq)) {
2648ab96fd8SJohn Baldwin 			printf("pci_cfgintr: %d:%d INT%c BIOS irq %d\n", bus,
2658ab96fd8SJohn Baldwin 			    device, 'A' + pin - 1, oldirq);
2668ab96fd8SJohn Baldwin 			return (oldirq);
2678ab96fd8SJohn Baldwin 		}
268ce494452SWarner Losh 
269ce494452SWarner Losh 		/*
270ce494452SWarner Losh 		 * We try to find a linked interrupt, then we look to see
271ce494452SWarner Losh 		 * if the interrupt is uniquely routed, then we look for
272ce494452SWarner Losh 		 * a virgin interrupt.  The virgin interrupt should return
273ce494452SWarner Losh 		 * an interrupt we can route, but if that fails, maybe we
274ce494452SWarner Losh 		 * should try harder to route a different interrupt.
275ce494452SWarner Losh 		 * However, experience has shown that that's rarely the
276ce494452SWarner Losh 		 * failure mode we see.
277ce494452SWarner Losh 		 */
278099d058bSMike Smith 		irq = pci_cfgintr_linked(pe, pin);
279ce494452SWarner Losh 		if (irq != PCI_INVALID_IRQ)
280ce494452SWarner Losh 			already = 1;
281ce494452SWarner Losh 		if (irq == PCI_INVALID_IRQ) {
282d626906bSWarner Losh 			irq = pci_cfgintr_unique(pe, pin);
283ce494452SWarner Losh 			if (irq != PCI_INVALID_IRQ)
284ce494452SWarner Losh 				errok = 1;
285ce494452SWarner Losh 		}
286e300f53cSWarner Losh 		if (irq == PCI_INVALID_IRQ)
287099d058bSMike Smith 			irq = pci_cfgintr_virgin(pe, pin);
288e300f53cSWarner Losh 		if (irq == PCI_INVALID_IRQ)
28954c9005fSWarner Losh 			break;
290099d058bSMike Smith 
2919d558634SMike Smith 		/*
292ce494452SWarner Losh 		 * Ask the BIOS to route the interrupt.  If we picked an
293ce494452SWarner Losh 		 * interrupt that failed, we should really try other
294ce494452SWarner Losh 		 * choices that the BIOS offers us.
295ce494452SWarner Losh 		 *
296ce494452SWarner Losh 		 * For uniquely routed interrupts, we need to try
297ce494452SWarner Losh 		 * to route them on some machines.  Yet other machines
298ce494452SWarner Losh 		 * fail to route, so we have to pretend that in that
299ce494452SWarner Losh 		 * case it worked.  Isn't pc hardware fun?
300ce494452SWarner Losh 		 *
301ce494452SWarner Losh 		 * NOTE: if we want to whack hardware to do this, then
302ce494452SWarner Losh 		 * I think the right way to do that would be to have
303ce494452SWarner Losh 		 * bridge drivers that do this.  I'm not sure that the
304ce494452SWarner Losh 		 * $PIR table would be valid for those interrupt
305ce494452SWarner Losh 		 * routers.
3069d558634SMike Smith 		 */
3079d558634SMike Smith 		args.eax = PCIBIOS_ROUTE_INTERRUPT;
3089d558634SMike Smith 		args.ebx = (bus << 8) | (device << 3);
309e300f53cSWarner Losh 		/* pin value is 0xa - 0xd */
310e300f53cSWarner Losh 		args.ecx = (irq << 8) | (0xa + pin - 1);
311e300f53cSWarner Losh 		if (!already &&
312ce494452SWarner Losh 		    bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL)) &&
313ce494452SWarner Losh 		    !errok) {
314d3b6477aSWarner Losh 			PRVERB(("pci_cfgintr: ROUTE_INTERRUPT failed.\n"));
315e300f53cSWarner Losh 			return(PCI_INVALID_IRQ);
316d626906bSWarner Losh 		}
317e300f53cSWarner Losh 		printf("pci_cfgintr: %d:%d INT%c routed to irq %d\n", bus,
318e300f53cSWarner Losh 		    device, 'A' + pin - 1, irq);
3199d558634SMike Smith 		return(irq);
32054c9005fSWarner Losh 	}
321099d058bSMike Smith 
322e300f53cSWarner Losh 	PRVERB(("pci_cfgintr: can't route an interrupt to %d:%d INT%c\n", bus,
323e300f53cSWarner Losh 	    device, 'A' + pin - 1));
324e300f53cSWarner Losh 	return(PCI_INVALID_IRQ);
325099d058bSMike Smith }
326099d058bSMike Smith 
327099d058bSMike Smith /*
3288ab96fd8SJohn Baldwin  * Check to see if an existing IRQ setting is valid.
3298ab96fd8SJohn Baldwin  */
3308ab96fd8SJohn Baldwin static int
3318ab96fd8SJohn Baldwin pci_cfgintr_valid(struct PIR_entry *pe, int pin, int irq)
3328ab96fd8SJohn Baldwin {
3338ab96fd8SJohn Baldwin 	uint32_t irqmask;
3348ab96fd8SJohn Baldwin 
3358ab96fd8SJohn Baldwin 	if (!PCI_INTERRUPT_VALID(irq))
3368ab96fd8SJohn Baldwin 		return (0);
3378ab96fd8SJohn Baldwin 	irqmask = pe->pe_intpin[pin - 1].irqs;
3388ab96fd8SJohn Baldwin 	if (irqmask & (1 << irq)) {
3398ab96fd8SJohn Baldwin 		PRVERB(("pci_cfgintr_valid: BIOS irq %d is valid\n", irq));
3408ab96fd8SJohn Baldwin 		return (1);
3418ab96fd8SJohn Baldwin 	}
3428ab96fd8SJohn Baldwin 	return (0);
3438ab96fd8SJohn Baldwin }
3448ab96fd8SJohn Baldwin 
3458ab96fd8SJohn Baldwin /*
346099d058bSMike Smith  * Look to see if the routing table claims this pin is uniquely routed.
347099d058bSMike Smith  */
348099d058bSMike Smith static int
349099d058bSMike Smith pci_cfgintr_unique(struct PIR_entry *pe, int pin)
350099d058bSMike Smith {
351099d058bSMike Smith 	int		irq;
352d5ccecfaSWarner Losh 	uint32_t	irqmask;
353099d058bSMike Smith 
354d5ccecfaSWarner Losh 	irqmask = pe->pe_intpin[pin - 1].irqs;
355d5ccecfaSWarner Losh 	if (irqmask != 0 && powerof2(irqmask)) {
356d5ccecfaSWarner Losh 		irq = ffs(irqmask) - 1;
357d626906bSWarner Losh 		PRVERB(("pci_cfgintr_unique: hard-routed to irq %d\n", irq));
358099d058bSMike Smith 		return(irq);
359099d058bSMike Smith 	}
360e300f53cSWarner Losh 	return(PCI_INVALID_IRQ);
361099d058bSMike Smith }
362099d058bSMike Smith 
363099d058bSMike Smith /*
364099d058bSMike Smith  * Look for another device which shares the same link byte and
365099d058bSMike Smith  * already has a unique IRQ, or which has had one routed already.
366099d058bSMike Smith  */
367099d058bSMike Smith static int
368099d058bSMike Smith pci_cfgintr_linked(struct PIR_entry *pe, int pin)
369099d058bSMike Smith {
370099d058bSMike Smith 	struct PIR_entry	*oe;
371099d058bSMike Smith 	struct PIR_intpin	*pi;
372099d058bSMike Smith 	int			i, j, irq;
373099d058bSMike Smith 
374099d058bSMike Smith 	/*
375099d058bSMike Smith 	 * Scan table slots.
376099d058bSMike Smith 	 */
377e300f53cSWarner Losh 	for (i = 0, oe = &pci_route_table->pt_entry[0]; i < pci_route_count;
378e300f53cSWarner Losh 	     i++, oe++) {
379099d058bSMike Smith 		/* scan interrupt pins */
380099d058bSMike Smith 		for (j = 0, pi = &oe->pe_intpin[0]; j < 4; j++, pi++) {
381099d058bSMike Smith 
382e300f53cSWarner Losh 			/* don't look at the entry we're trying to match */
383099d058bSMike Smith 			if ((pe == oe) && (i == (pin - 1)))
384099d058bSMike Smith 				continue;
385099d058bSMike Smith 			/* compare link bytes */
386099d058bSMike Smith 			if (pi->link != pe->pe_intpin[pin - 1].link)
387099d058bSMike Smith 				continue;
388099d058bSMike Smith 			/* link destination mapped to a unique interrupt? */
389d5ccecfaSWarner Losh 			if (pi->irqs != 0 && powerof2(pi->irqs)) {
390099d058bSMike Smith 				irq = ffs(pi->irqs) - 1;
391d626906bSWarner Losh 				PRVERB(("pci_cfgintr_linked: linked (%x) to hard-routed irq %d\n",
392d626906bSWarner Losh 				    pi->link, irq));
393099d058bSMike Smith 				return(irq);
394099d058bSMike Smith 			}
395099d058bSMike Smith 
396e300f53cSWarner Losh 			/*
397e300f53cSWarner Losh 			 * look for the real PCI device that matches this
398e300f53cSWarner Losh 			 * table entry
399e300f53cSWarner Losh 			 */
400e300f53cSWarner Losh 			irq = pci_cfgintr_search(pe, oe->pe_bus, oe->pe_device,
401810cb9efSJohn Baldwin 			    j + 1, pin);
402e300f53cSWarner Losh 			if (irq != PCI_INVALID_IRQ)
403099d058bSMike Smith 				return(irq);
404099d058bSMike Smith 		}
405099d058bSMike Smith 	}
406e300f53cSWarner Losh 	return(PCI_INVALID_IRQ);
407099d058bSMike Smith }
408099d058bSMike Smith 
409099d058bSMike Smith /*
410099d058bSMike Smith  * Scan for the real PCI device at (bus)/(device) using intpin (matchpin) and
411099d058bSMike Smith  * see if it has already been assigned an interrupt.
412099d058bSMike Smith  */
413099d058bSMike Smith static int
414099d058bSMike Smith pci_cfgintr_search(struct PIR_entry *pe, int bus, int device, int matchpin, int pin)
415099d058bSMike Smith {
416099d058bSMike Smith 	devclass_t		pci_devclass;
417099d058bSMike Smith 	device_t		*pci_devices;
418099d058bSMike Smith 	int			pci_count;
419099d058bSMike Smith 	device_t		*pci_children;
420099d058bSMike Smith 	int			pci_childcount;
421099d058bSMike Smith 	device_t		*busp, *childp;
422099d058bSMike Smith 	int			i, j, irq;
423099d058bSMike Smith 
424099d058bSMike Smith 	/*
425099d058bSMike Smith 	 * Find all the PCI busses.
426099d058bSMike Smith 	 */
427099d058bSMike Smith 	pci_count = 0;
428099d058bSMike Smith 	if ((pci_devclass = devclass_find("pci")) != NULL)
429099d058bSMike Smith 		devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
430099d058bSMike Smith 
431099d058bSMike Smith 	/*
432099d058bSMike Smith 	 * Scan all the PCI busses/devices looking for this one.
433099d058bSMike Smith 	 */
434e300f53cSWarner Losh 	irq = PCI_INVALID_IRQ;
435e300f53cSWarner Losh 	for (i = 0, busp = pci_devices; (i < pci_count) && (irq == PCI_INVALID_IRQ);
436e300f53cSWarner Losh 	     i++, busp++) {
437099d058bSMike Smith 		pci_childcount = 0;
438099d058bSMike Smith 		device_get_children(*busp, &pci_children, &pci_childcount);
439099d058bSMike Smith 
440e300f53cSWarner Losh 		for (j = 0, childp = pci_children; j < pci_childcount; j++,
441e300f53cSWarner Losh 		    childp++) {
442099d058bSMike Smith 			if ((pci_get_bus(*childp) == bus) &&
443099d058bSMike Smith 			    (pci_get_slot(*childp) == device) &&
4441cf5f555SWarner Losh 			    (pci_get_intpin(*childp) == matchpin)) {
4458ce1ab3aSWarner Losh 				irq = pci_i386_map_intline(pci_get_irq(*childp));
446e300f53cSWarner Losh 				if (irq != PCI_INVALID_IRQ)
447d626906bSWarner Losh 					PRVERB(("pci_cfgintr_search: linked (%x) to configured irq %d at %d:%d:%d\n",
44885fab963SMike Smith 					    pe->pe_intpin[pin - 1].link, irq,
449e300f53cSWarner Losh 					    pci_get_bus(*childp),
450e300f53cSWarner Losh 					    pci_get_slot(*childp),
451e300f53cSWarner Losh 					    pci_get_function(*childp)));
4526c9eb5f3SMike Smith 				break;
4536c9eb5f3SMike Smith 			}
4546c9eb5f3SMike Smith 		}
4556c9eb5f3SMike Smith 		if (pci_children != NULL)
4566c9eb5f3SMike Smith 			free(pci_children, M_TEMP);
4576c9eb5f3SMike Smith 	}
4586c9eb5f3SMike Smith 	if (pci_devices != NULL)
4596c9eb5f3SMike Smith 		free(pci_devices, M_TEMP);
460099d058bSMike Smith 	return(irq);
461099d058bSMike Smith }
462099d058bSMike Smith 
463099d058bSMike Smith /*
464099d058bSMike Smith  * Pick a suitable IRQ from those listed as routable to this device.
465099d058bSMike Smith  */
466099d058bSMike Smith static int
467099d058bSMike Smith pci_cfgintr_virgin(struct PIR_entry *pe, int pin)
468099d058bSMike Smith {
469099d058bSMike Smith 	int		irq, ibit;
470099d058bSMike Smith 
471e300f53cSWarner Losh 	/*
472e300f53cSWarner Losh 	 * first scan the set of PCI-only interrupts and see if any of these
473e300f53cSWarner Losh 	 * are routable
474e300f53cSWarner Losh 	 */
475099d058bSMike Smith 	for (irq = 0; irq < 16; irq++) {
476099d058bSMike Smith 		ibit = (1 << irq);
477099d058bSMike Smith 
478099d058bSMike Smith 		/* can we use this interrupt? */
479099d058bSMike Smith 		if ((pci_route_table->pt_header.ph_pci_irqs & ibit) &&
480099d058bSMike Smith 		    (pe->pe_intpin[pin - 1].irqs & ibit)) {
481d626906bSWarner Losh 			PRVERB(("pci_cfgintr_virgin: using routable PCI-only interrupt %d\n", irq));
482099d058bSMike Smith 			return(irq);
483099d058bSMike Smith 		}
484099d058bSMike Smith 	}
485099d058bSMike Smith 
486099d058bSMike Smith 	/* life is tough, so just pick an interrupt */
487099d058bSMike Smith 	for (irq = 0; irq < 16; irq++) {
488099d058bSMike Smith 		ibit = (1 << irq);
489e86bd39aSWarner Losh 		if ((ibit & pci_irq_override_mask) == 0)
490e86bd39aSWarner Losh 			continue;
491099d058bSMike Smith 		if (pe->pe_intpin[pin - 1].irqs & ibit) {
492d626906bSWarner Losh 			PRVERB(("pci_cfgintr_virgin: using routable interrupt %d\n", irq));
493099d058bSMike Smith 			return(irq);
494099d058bSMike Smith 		}
495099d058bSMike Smith 	}
496e300f53cSWarner Losh 	return(PCI_INVALID_IRQ);
49754c9005fSWarner Losh }
49854c9005fSWarner Losh 
499fbabd7beSJohn Baldwin static void
500fbabd7beSJohn Baldwin pci_print_irqmask(u_int16_t irqs)
501fbabd7beSJohn Baldwin {
502fbabd7beSJohn Baldwin 	int i, first;
503fbabd7beSJohn Baldwin 
504fbabd7beSJohn Baldwin 	if (irqs == 0) {
505fbabd7beSJohn Baldwin 		printf("none");
506fbabd7beSJohn Baldwin 		return;
507fbabd7beSJohn Baldwin 	}
508fbabd7beSJohn Baldwin 	first = 1;
509fbabd7beSJohn Baldwin 	for (i = 0; i < 16; i++, irqs >>= 1)
510fbabd7beSJohn Baldwin 		if (irqs & 1) {
511fbabd7beSJohn Baldwin 			if (!first)
512fbabd7beSJohn Baldwin 				printf(" ");
513fbabd7beSJohn Baldwin 			else
514fbabd7beSJohn Baldwin 				first = 0;
515fbabd7beSJohn Baldwin 			printf("%d", i);
516fbabd7beSJohn Baldwin 		}
517fbabd7beSJohn Baldwin }
518fbabd7beSJohn Baldwin 
519fbabd7beSJohn Baldwin /*
520fbabd7beSJohn Baldwin  * Dump the contents of a PCI BIOS Interrupt Routing Table to the console.
521fbabd7beSJohn Baldwin  */
522fbabd7beSJohn Baldwin static void
523fbabd7beSJohn Baldwin pci_print_route_table(struct PIR_table *prt, int size)
524fbabd7beSJohn Baldwin {
525fbabd7beSJohn Baldwin 	struct PIR_entry *entry;
526fbabd7beSJohn Baldwin 	struct PIR_intpin *intpin;
527fbabd7beSJohn Baldwin 	int i, pin;
528fbabd7beSJohn Baldwin 
529fbabd7beSJohn Baldwin 	printf("PCI-Only Interrupts: ");
530fbabd7beSJohn Baldwin 	pci_print_irqmask(prt->pt_header.ph_pci_irqs);
531fbabd7beSJohn Baldwin 	printf("\nLocation  Bus Device Pin  Link  IRQs\n");
532fbabd7beSJohn Baldwin 	entry = &prt->pt_entry[0];
533fbabd7beSJohn Baldwin 	for (i = 0; i < size; i++, entry++) {
534fbabd7beSJohn Baldwin 		intpin = &entry->pe_intpin[0];
535fbabd7beSJohn Baldwin 		for (pin = 0; pin < 4; pin++, intpin++)
536fbabd7beSJohn Baldwin 			if (intpin->link != 0) {
537fbabd7beSJohn Baldwin 				if (entry->pe_slot == 0)
538fbabd7beSJohn Baldwin 					printf("embedded ");
539fbabd7beSJohn Baldwin 				else
540fbabd7beSJohn Baldwin 					printf("slot %-3d ", entry->pe_slot);
541fbabd7beSJohn Baldwin 				printf(" %3d  %3d    %c   0x%02x  ",
542fbabd7beSJohn Baldwin 				    entry->pe_bus, entry->pe_device,
543fbabd7beSJohn Baldwin 				    'A' + pin, intpin->link);
544fbabd7beSJohn Baldwin 				pci_print_irqmask(intpin->irqs);
545fbabd7beSJohn Baldwin 				printf("\n");
546fbabd7beSJohn Baldwin 			}
547fbabd7beSJohn Baldwin 	}
548fbabd7beSJohn Baldwin }
54954c9005fSWarner Losh 
55054c9005fSWarner Losh /*
551c3ba1376SJohn Baldwin  * See if any interrupts for a given PCI bus are routed in the PIR.  Don't
552c3ba1376SJohn Baldwin  * even bother looking if the BIOS doesn't support routing anyways.
553c3ba1376SJohn Baldwin  */
554c3ba1376SJohn Baldwin int
555c3ba1376SJohn Baldwin pci_probe_route_table(int bus)
556c3ba1376SJohn Baldwin {
557c3ba1376SJohn Baldwin 	int i;
558c3ba1376SJohn Baldwin 	u_int16_t v;
559c3ba1376SJohn Baldwin 
560c3ba1376SJohn Baldwin 	v = pcibios_get_version();
561c3ba1376SJohn Baldwin 	if (v < 0x0210)
562c3ba1376SJohn Baldwin 		return (0);
563c3ba1376SJohn Baldwin 	for (i = 0; i < pci_route_count; i++)
564c3ba1376SJohn Baldwin 		if (pci_route_table->pt_entry[i].pe_bus == bus)
565c3ba1376SJohn Baldwin 			return (1);
566c3ba1376SJohn Baldwin 	return (0);
567c3ba1376SJohn Baldwin }
568c3ba1376SJohn Baldwin 
56912a02d6eSMike Smith /*
57012a02d6eSMike Smith  * Configuration space access using direct register operations
57112a02d6eSMike Smith  */
572ac19f918SStefan Eßer 
5735bec6157SStefan Eßer /* enable configuration space accesses and return data port address */
574a3adc4f8SStefan Eßer static int
5755bec6157SStefan Eßer pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
5765bec6157SStefan Eßer {
5775bec6157SStefan Eßer 	int dataport = 0;
5785bec6157SStefan Eßer 
5795bec6157SStefan Eßer 	if (bus <= PCI_BUSMAX
5805bec6157SStefan Eßer 	    && slot < devmax
5815bec6157SStefan Eßer 	    && func <= PCI_FUNCMAX
5825bec6157SStefan Eßer 	    && reg <= PCI_REGMAX
5835bec6157SStefan Eßer 	    && bytes != 3
5845bec6157SStefan Eßer 	    && (unsigned) bytes <= 4
5855bec6157SStefan Eßer 	    && (reg & (bytes - 1)) == 0) {
5865bec6157SStefan Eßer 		switch (cfgmech) {
5875bec6157SStefan Eßer 		case 1:
588b3daa02eSStefan Eßer 			outl(CONF1_ADDR_PORT, (1 << 31)
589b3daa02eSStefan Eßer 			    | (bus << 16) | (slot << 11)
590b3daa02eSStefan Eßer 			    | (func << 8) | (reg & ~0x03));
591b3daa02eSStefan Eßer 			dataport = CONF1_DATA_PORT + (reg & 0x03);
5925bec6157SStefan Eßer 			break;
5935bec6157SStefan Eßer 		case 2:
5945bec6157SStefan Eßer 			outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
5955bec6157SStefan Eßer 			outb(CONF2_FORWARD_PORT, bus);
5965bec6157SStefan Eßer 			dataport = 0xc000 | (slot << 8) | reg;
5975bec6157SStefan Eßer 			break;
5985bec6157SStefan Eßer 		}
5995bec6157SStefan Eßer 	}
6005bec6157SStefan Eßer 	return (dataport);
6015bec6157SStefan Eßer }
6025bec6157SStefan Eßer 
6035bec6157SStefan Eßer /* disable configuration space accesses */
6045bec6157SStefan Eßer static void
6055bec6157SStefan Eßer pci_cfgdisable(void)
6065bec6157SStefan Eßer {
6075bec6157SStefan Eßer 	switch (cfgmech) {
6085bec6157SStefan Eßer 	case 1:
6095bec6157SStefan Eßer 		outl(CONF1_ADDR_PORT, 0);
6105bec6157SStefan Eßer 		break;
6115bec6157SStefan Eßer 	case 2:
6125bec6157SStefan Eßer 		outb(CONF2_ENABLE_PORT, 0);
6135bec6157SStefan Eßer 		outb(CONF2_FORWARD_PORT, 0);
6145bec6157SStefan Eßer 		break;
6155bec6157SStefan Eßer 	}
6165bec6157SStefan Eßer }
6175bec6157SStefan Eßer 
618300451c4SMike Smith static int
61921c3015aSDoug Rabson pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
6205bec6157SStefan Eßer {
6215bec6157SStefan Eßer 	int data = -1;
6225bec6157SStefan Eßer 	int port;
6235bec6157SStefan Eßer 
624af3d516fSPeter Wemm 	mtx_lock_spin(&pcicfg_mtx);
62521c3015aSDoug Rabson 	port = pci_cfgenable(bus, slot, func, reg, bytes);
6265bec6157SStefan Eßer 	if (port != 0) {
6275bec6157SStefan Eßer 		switch (bytes) {
6285bec6157SStefan Eßer 		case 1:
6295bec6157SStefan Eßer 			data = inb(port);
6305bec6157SStefan Eßer 			break;
6315bec6157SStefan Eßer 		case 2:
6325bec6157SStefan Eßer 			data = inw(port);
6335bec6157SStefan Eßer 			break;
6345bec6157SStefan Eßer 		case 4:
6355bec6157SStefan Eßer 			data = inl(port);
6365bec6157SStefan Eßer 			break;
6375bec6157SStefan Eßer 		}
6385bec6157SStefan Eßer 		pci_cfgdisable();
6395bec6157SStefan Eßer 	}
640af3d516fSPeter Wemm 	mtx_unlock_spin(&pcicfg_mtx);
6415bec6157SStefan Eßer 	return (data);
6425bec6157SStefan Eßer }
6435bec6157SStefan Eßer 
644300451c4SMike Smith static void
64521c3015aSDoug Rabson pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
6465bec6157SStefan Eßer {
6475bec6157SStefan Eßer 	int port;
6485bec6157SStefan Eßer 
649af3d516fSPeter Wemm 	mtx_lock_spin(&pcicfg_mtx);
65021c3015aSDoug Rabson 	port = pci_cfgenable(bus, slot, func, reg, bytes);
6515bec6157SStefan Eßer 	if (port != 0) {
6525bec6157SStefan Eßer 		switch (bytes) {
6535bec6157SStefan Eßer 		case 1:
6545bec6157SStefan Eßer 			outb(port, data);
6555bec6157SStefan Eßer 			break;
6565bec6157SStefan Eßer 		case 2:
6575bec6157SStefan Eßer 			outw(port, data);
6585bec6157SStefan Eßer 			break;
6595bec6157SStefan Eßer 		case 4:
6605bec6157SStefan Eßer 			outl(port, data);
6615bec6157SStefan Eßer 			break;
6625bec6157SStefan Eßer 		}
6635bec6157SStefan Eßer 		pci_cfgdisable();
6645bec6157SStefan Eßer 	}
665af3d516fSPeter Wemm 	mtx_unlock_spin(&pcicfg_mtx);
6665bec6157SStefan Eßer }
6675bec6157SStefan Eßer 
66812a02d6eSMike Smith /* check whether the configuration mechanism has been correctly identified */
6695bec6157SStefan Eßer static int
6705bec6157SStefan Eßer pci_cfgcheck(int maxdev)
671a3adc4f8SStefan Eßer {
672984de797SWarner Losh 	uint32_t id, class;
673984de797SWarner Losh 	uint8_t header;
674984de797SWarner Losh 	uint8_t device;
675af3d516fSPeter Wemm 	int port;
676a3adc4f8SStefan Eßer 
6775bec6157SStefan Eßer 	if (bootverbose)
6785bec6157SStefan Eßer 		printf("pci_cfgcheck:\tdevice ");
67977b57314SStefan Eßer 
6805bec6157SStefan Eßer 	for (device = 0; device < maxdev; device++) {
681c7483249SStefan Eßer 		if (bootverbose)
682c7483249SStefan Eßer 			printf("%d ", device);
6835bec6157SStefan Eßer 
684af3d516fSPeter Wemm 		port = pci_cfgenable(0, device, 0, 0, 4);
685af3d516fSPeter Wemm 		id = inl(port);
686984de797SWarner Losh 		if (id == 0 || id == 0xffffffff)
68781cf5d7aSStefan Eßer 			continue;
68881cf5d7aSStefan Eßer 
689af3d516fSPeter Wemm 		port = pci_cfgenable(0, device, 0, 8, 4);
690af3d516fSPeter Wemm 		class = inl(port) >> 8;
69181cf5d7aSStefan Eßer 		if (bootverbose)
6925bec6157SStefan Eßer 			printf("[class=%06x] ", class);
6938277ac25SStefan Eßer 		if (class == 0 || (class & 0xf870ff) != 0)
69481cf5d7aSStefan Eßer 			continue;
69581cf5d7aSStefan Eßer 
696af3d516fSPeter Wemm 		port = pci_cfgenable(0, device, 0, 14, 1);
697af3d516fSPeter Wemm 		header = inb(port);
69881cf5d7aSStefan Eßer 		if (bootverbose)
6995bec6157SStefan Eßer 			printf("[hdr=%02x] ", header);
7005bec6157SStefan Eßer 		if ((header & 0x7e) != 0)
70181cf5d7aSStefan Eßer 			continue;
70281cf5d7aSStefan Eßer 
7035bec6157SStefan Eßer 		if (bootverbose)
7045bec6157SStefan Eßer 			printf("is there (id=%08x)\n", id);
7055bec6157SStefan Eßer 
7065bec6157SStefan Eßer 		pci_cfgdisable();
7075bec6157SStefan Eßer 		return (1);
708a3adc4f8SStefan Eßer 	}
709c7483249SStefan Eßer 	if (bootverbose)
710c7483249SStefan Eßer 		printf("-- nothing found\n");
7115bec6157SStefan Eßer 
7125bec6157SStefan Eßer 	pci_cfgdisable();
7135bec6157SStefan Eßer 	return (0);
714a3adc4f8SStefan Eßer }
715d7ea35fcSStefan Eßer 
7168dc26439SPeter Wemm static int
717300451c4SMike Smith pcireg_cfgopen(void)
718ac19f918SStefan Eßer {
719984de797SWarner Losh 	uint32_t mode1res, oldval1;
720984de797SWarner Losh 	uint8_t mode2res, oldval2;
7210847c06dSStefan Eßer 
722287911bdSStefan Eßer 	oldval1 = inl(CONF1_ADDR_PORT);
723a3adc4f8SStefan Eßer 
72477b57314SStefan Eßer 	if (bootverbose) {
725984de797SWarner Losh 		printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
7265bec6157SStefan Eßer 		    oldval1);
727a3adc4f8SStefan Eßer 	}
728a3adc4f8SStefan Eßer 
7290e2f699bSStefan Eßer 	if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
730287911bdSStefan Eßer 
7315bec6157SStefan Eßer 		cfgmech = 1;
7325bec6157SStefan Eßer 		devmax = 32;
73377b57314SStefan Eßer 
73477b57314SStefan Eßer 		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
73521e25fa6SJohn Baldwin 		DELAY(1);
73677b57314SStefan Eßer 		mode1res = inl(CONF1_ADDR_PORT);
737287911bdSStefan Eßer 		outl(CONF1_ADDR_PORT, oldval1);
73877b57314SStefan Eßer 
73977b57314SStefan Eßer 		if (bootverbose)
740984de797SWarner Losh 			printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n",
74177b57314SStefan Eßer 			    mode1res, CONF1_ENABLE_CHK);
74277b57314SStefan Eßer 
74377b57314SStefan Eßer 		if (mode1res) {
7445bec6157SStefan Eßer 			if (pci_cfgcheck(32))
7455bec6157SStefan Eßer 				return (cfgmech);
7465bec6157SStefan Eßer 		}
74777b57314SStefan Eßer 
74877b57314SStefan Eßer 		outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
74977b57314SStefan Eßer 		mode1res = inl(CONF1_ADDR_PORT);
750287911bdSStefan Eßer 		outl(CONF1_ADDR_PORT, oldval1);
75177b57314SStefan Eßer 
75277b57314SStefan Eßer 		if (bootverbose)
753984de797SWarner Losh 			printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n",
75477b57314SStefan Eßer 			    mode1res, CONF1_ENABLE_CHK1);
75577b57314SStefan Eßer 
756c7483249SStefan Eßer 		if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
7575bec6157SStefan Eßer 			if (pci_cfgcheck(32))
7585bec6157SStefan Eßer 				return (cfgmech);
759287911bdSStefan Eßer 		}
7605bec6157SStefan Eßer 	}
76177b57314SStefan Eßer 
762287911bdSStefan Eßer 	oldval2 = inb(CONF2_ENABLE_PORT);
763287911bdSStefan Eßer 
764287911bdSStefan Eßer 	if (bootverbose) {
7655bec6157SStefan Eßer 		printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
7665bec6157SStefan Eßer 		    oldval2);
767287911bdSStefan Eßer 	}
768287911bdSStefan Eßer 
769287911bdSStefan Eßer 	if ((oldval2 & 0xf0) == 0) {
770c7483249SStefan Eßer 
7715bec6157SStefan Eßer 		cfgmech = 2;
7725bec6157SStefan Eßer 		devmax = 16;
77377b57314SStefan Eßer 
774287911bdSStefan Eßer 		outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
775287911bdSStefan Eßer 		mode2res = inb(CONF2_ENABLE_PORT);
776287911bdSStefan Eßer 		outb(CONF2_ENABLE_PORT, oldval2);
777287911bdSStefan Eßer 
778287911bdSStefan Eßer 		if (bootverbose)
7795bec6157SStefan Eßer 			printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
780287911bdSStefan Eßer 			    mode2res, CONF2_ENABLE_CHK);
781287911bdSStefan Eßer 
782287911bdSStefan Eßer 		if (mode2res == CONF2_ENABLE_RES) {
783287911bdSStefan Eßer 			if (bootverbose)
7845bec6157SStefan Eßer 				printf("pci_open(2a):\tnow trying mechanism 2\n");
785287911bdSStefan Eßer 
7865bec6157SStefan Eßer 			if (pci_cfgcheck(16))
7875bec6157SStefan Eßer 				return (cfgmech);
788287911bdSStefan Eßer 		}
789287911bdSStefan Eßer 	}
79077b57314SStefan Eßer 
7915bec6157SStefan Eßer 	cfgmech = 0;
7925bec6157SStefan Eßer 	devmax = 0;
7935bec6157SStefan Eßer 	return (cfgmech);
794ac19f918SStefan Eßer }
7958dc26439SPeter Wemm 
796