xref: /netbsd-src/sys/arch/x86/pci/pci_addr_fixup.c (revision befe278cf16e7a31f3db42ecf2f046b2a0a6ac38)
1*befe278cSmaxv /*	$NetBSD: pci_addr_fixup.c,v 1.10 2017/07/28 14:26:50 maxv Exp $	*/
29709f2afSjmcneill 
39709f2afSjmcneill /*-
49709f2afSjmcneill  * Copyright (c) 2000 UCHIYAMA Yasushi.  All rights reserved.
59709f2afSjmcneill  *
69709f2afSjmcneill  * Redistribution and use in source and binary forms, with or without
79709f2afSjmcneill  * modification, are permitted provided that the following conditions
89709f2afSjmcneill  * are met:
99709f2afSjmcneill  * 1. Redistributions of source code must retain the above copyright
109709f2afSjmcneill  *    notice, this list of conditions and the following disclaimer.
119709f2afSjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
129709f2afSjmcneill  *    notice, this list of conditions and the following disclaimer in the
139709f2afSjmcneill  *    documentation and/or other materials provided with the distribution.
149709f2afSjmcneill  * 3. The name of the author may not be used to endorse or promote products
159709f2afSjmcneill  *    derived from this software without specific prior written permission.
169709f2afSjmcneill  *
179709f2afSjmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
189709f2afSjmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
199709f2afSjmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
209709f2afSjmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
219709f2afSjmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
229709f2afSjmcneill  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
239709f2afSjmcneill  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
249709f2afSjmcneill  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
259709f2afSjmcneill  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
269709f2afSjmcneill  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
279709f2afSjmcneill  */
289709f2afSjmcneill 
299709f2afSjmcneill #include <sys/cdefs.h>
30*befe278cSmaxv __KERNEL_RCSID(0, "$NetBSD: pci_addr_fixup.c,v 1.10 2017/07/28 14:26:50 maxv Exp $");
319709f2afSjmcneill 
329709f2afSjmcneill #include <sys/param.h>
339709f2afSjmcneill #include <sys/systm.h>
349709f2afSjmcneill #include <sys/kernel.h>
359709f2afSjmcneill #include <sys/device.h>
369709f2afSjmcneill #include <sys/extent.h>
379709f2afSjmcneill 
38391925c7Sdyoung #include <sys/bus.h>
399709f2afSjmcneill 
409709f2afSjmcneill #include <dev/pci/pcireg.h>
419709f2afSjmcneill #include <dev/pci/pcivar.h>
429709f2afSjmcneill #include <dev/pci/pcidevs.h>
439709f2afSjmcneill 
449709f2afSjmcneill #include <x86/pci/pci_addr_fixup.h>
459709f2afSjmcneill 
469709f2afSjmcneill struct pciaddr pciaddr;
479709f2afSjmcneill 
4835fd1a8bSdyoung static void	pciaddr_resource_reserve(pci_chipset_tag_t, pcitag_t, void *);
4935fd1a8bSdyoung static int	pciaddr_do_resource_reserve(pci_chipset_tag_t, pcitag_t, int,
509709f2afSjmcneill     				    void *, int, bus_addr_t *, bus_size_t);
5135fd1a8bSdyoung static void	pciaddr_resource_allocate(pci_chipset_tag_t, pcitag_t, void *);
5235fd1a8bSdyoung static int	pciaddr_do_resource_allocate(pci_chipset_tag_t, pcitag_t, int,
539709f2afSjmcneill 				     void *, int, bus_addr_t *, bus_size_t);
5435fd1a8bSdyoung static int	device_is_agp(pci_chipset_tag_t, pcitag_t);
559709f2afSjmcneill 
569709f2afSjmcneill #define PCIADDR_MEM_START	0x0
579709f2afSjmcneill #define PCIADDR_MEM_END		0xffffffff
589709f2afSjmcneill #define PCIADDR_PORT_START	0x0
599709f2afSjmcneill #define PCIADDR_PORT_END	0xffff
609709f2afSjmcneill 
619709f2afSjmcneill /* for ISA devices */
629709f2afSjmcneill #define PCIADDR_ISAPORT_RESERVE	0x5800 /* empirical value */
639709f2afSjmcneill #define PCIADDR_ISAMEM_RESERVE	(16 * 1024 * 1024)
649709f2afSjmcneill 
659709f2afSjmcneill void
pci_addr_fixup(pci_chipset_tag_t pc,int maxbus)669709f2afSjmcneill pci_addr_fixup(pci_chipset_tag_t pc, int maxbus)
679709f2afSjmcneill {
689709f2afSjmcneill 	extern paddr_t avail_end;
699709f2afSjmcneill 	const char *verbose_header =
709709f2afSjmcneill 		"[%s]-----------------------\n"
719709f2afSjmcneill 		"  device vendor product\n"
729709f2afSjmcneill 		"  register space address    size\n"
739709f2afSjmcneill 		"--------------------------------------------\n";
749709f2afSjmcneill 	const char *verbose_footer =
759709f2afSjmcneill 		"--------------------------[%3d devices bogus]\n";
769709f2afSjmcneill 	const struct {
779709f2afSjmcneill 		bus_addr_t start;
789709f2afSjmcneill 		bus_size_t size;
799709f2afSjmcneill 		const char *name;
809709f2afSjmcneill 	} system_reserve [] = {
819709f2afSjmcneill 		{ 0xfec00000, 0x100000, "I/O APIC" },
829709f2afSjmcneill 		{ 0xfee00000, 0x100000, "Local APIC" },
839709f2afSjmcneill 		{ 0xfffe0000, 0x20000, "BIOS PROM" },
849709f2afSjmcneill 		{ 0, 0, 0 }, /* terminator */
859709f2afSjmcneill 	}, *srp;
869709f2afSjmcneill 	paddr_t start;
879709f2afSjmcneill 	int error;
889709f2afSjmcneill 
899709f2afSjmcneill 	pciaddr.extent_mem = extent_create("PCI I/O memory space",
909709f2afSjmcneill 					   PCIADDR_MEM_START,
919709f2afSjmcneill 					   PCIADDR_MEM_END,
9289c9828dSpara 					   0, 0, EX_NOWAIT);
939709f2afSjmcneill 	KASSERT(pciaddr.extent_mem);
949709f2afSjmcneill 	pciaddr.extent_port = extent_create("PCI I/O port space",
959709f2afSjmcneill 					    PCIADDR_PORT_START,
969709f2afSjmcneill 					    PCIADDR_PORT_END,
9789c9828dSpara 					    0, 0, EX_NOWAIT);
989709f2afSjmcneill 	KASSERT(pciaddr.extent_port);
999709f2afSjmcneill 
1009709f2afSjmcneill 	/*
1019709f2afSjmcneill 	 * 1. check & reserve system BIOS setting.
1029709f2afSjmcneill 	 */
1039709f2afSjmcneill 	aprint_debug(verbose_header, "System BIOS Setting");
1049709f2afSjmcneill 	pci_device_foreach(pc, maxbus, pciaddr_resource_reserve, NULL);
1059709f2afSjmcneill 	aprint_debug(verbose_footer, pciaddr.nbogus);
1069709f2afSjmcneill 
1079709f2afSjmcneill 	/*
1089709f2afSjmcneill 	 * 2. reserve non-PCI area.
1099709f2afSjmcneill 	 */
1109709f2afSjmcneill 	for (srp = system_reserve; srp->size; srp++) {
1119709f2afSjmcneill 		error = extent_alloc_region(pciaddr.extent_mem, srp->start,
1129709f2afSjmcneill 					    srp->size,
1139709f2afSjmcneill 					    EX_NOWAIT| EX_MALLOCOK);
1149709f2afSjmcneill 		if (error != 0) {
11560c3292cSjmcneill 			aprint_error("WARNING: can't reserve area for %s.\n",
1169709f2afSjmcneill 			       srp->name);
1179709f2afSjmcneill 		}
1189709f2afSjmcneill 	}
1199709f2afSjmcneill 
1209709f2afSjmcneill 	/*
1219709f2afSjmcneill 	 * 3. determine allocation space
1229709f2afSjmcneill 	 */
1239709f2afSjmcneill 	start = x86_round_page(avail_end + 1);
1249709f2afSjmcneill 	if (start < PCIADDR_ISAMEM_RESERVE)
1259709f2afSjmcneill 		start = PCIADDR_ISAMEM_RESERVE;
1269709f2afSjmcneill 	pciaddr.mem_alloc_start = (start + 0x100000 + 1) & ~(0x100000 - 1);
1279709f2afSjmcneill 	pciaddr.port_alloc_start = PCIADDR_ISAPORT_RESERVE;
1289709f2afSjmcneill 	aprint_debug(" Physical memory end: 0x%08x\n PCI memory mapped I/O "
1299709f2afSjmcneill 			"space start: 0x%08x\n", (unsigned)avail_end,
1309709f2afSjmcneill 			(unsigned)pciaddr.mem_alloc_start);
1319709f2afSjmcneill 
1329709f2afSjmcneill 	if (pciaddr.nbogus == 0)
1339709f2afSjmcneill 		return; /* no need to fixup */
1349709f2afSjmcneill 
1359709f2afSjmcneill 	/*
1369709f2afSjmcneill 	 * 4. do fixup
1379709f2afSjmcneill 	 */
1389709f2afSjmcneill 	aprint_debug(verbose_header, "PCIBIOS fixup stage");
1399709f2afSjmcneill 	pciaddr.nbogus = 0;
1409709f2afSjmcneill 	pci_device_foreach_min(pc, 0, maxbus, pciaddr_resource_allocate, NULL);
1419709f2afSjmcneill 	aprint_debug(verbose_footer, pciaddr.nbogus);
1429709f2afSjmcneill 
1439709f2afSjmcneill }
1449709f2afSjmcneill 
14535fd1a8bSdyoung static void
pciaddr_resource_reserve(pci_chipset_tag_t pc,pcitag_t tag,void * context)1469709f2afSjmcneill pciaddr_resource_reserve(pci_chipset_tag_t pc, pcitag_t tag,
1479709f2afSjmcneill     void *context)
1489709f2afSjmcneill {
1499709f2afSjmcneill 	pciaddr_print_devid(pc, tag);
1509709f2afSjmcneill 	pciaddr_resource_manage(pc, tag,
1519709f2afSjmcneill 				pciaddr_do_resource_reserve,
1529709f2afSjmcneill 				&pciaddr);
1539709f2afSjmcneill }
1549709f2afSjmcneill 
15535fd1a8bSdyoung static void
pciaddr_resource_allocate(pci_chipset_tag_t pc,pcitag_t tag,void * context)1569709f2afSjmcneill pciaddr_resource_allocate(pci_chipset_tag_t pc, pcitag_t tag,
1579709f2afSjmcneill     void *context)
1589709f2afSjmcneill {
1599709f2afSjmcneill 	pciaddr_print_devid(pc, tag);
1609709f2afSjmcneill 	pciaddr_resource_manage(pc, tag,
1619709f2afSjmcneill 				pciaddr_do_resource_allocate,
1629709f2afSjmcneill 				&pciaddr);
1639709f2afSjmcneill }
1649709f2afSjmcneill 
1659709f2afSjmcneill void
pciaddr_resource_manage(pci_chipset_tag_t pc,pcitag_t tag,pciaddr_resource_manage_func_t func,void * ctx)1669709f2afSjmcneill pciaddr_resource_manage(pci_chipset_tag_t pc, pcitag_t tag,
1679709f2afSjmcneill     pciaddr_resource_manage_func_t func, void *ctx)
1689709f2afSjmcneill {
1699709f2afSjmcneill 	pcireg_t val, mask;
1709709f2afSjmcneill 	bus_addr_t addr;
1719709f2afSjmcneill 	bus_size_t size;
1729709f2afSjmcneill 	int error, useport, usemem, mapreg, type, reg_start, reg_end, width;
1739709f2afSjmcneill 
1749709f2afSjmcneill 	val = pci_conf_read(pc, tag, PCI_BHLC_REG);
1759709f2afSjmcneill 	switch (PCI_HDRTYPE_TYPE(val)) {
1769709f2afSjmcneill 	default:
17760c3292cSjmcneill 		aprint_error("WARNING: unknown PCI device header.");
1789709f2afSjmcneill 		pciaddr.nbogus++;
1799709f2afSjmcneill 		return;
18035fd1a8bSdyoung 	case PCI_HDRTYPE_DEVICE:
1819709f2afSjmcneill 		reg_start = PCI_MAPREG_START;
1829709f2afSjmcneill 		reg_end   = PCI_MAPREG_END;
1839709f2afSjmcneill 		break;
18435fd1a8bSdyoung 	case PCI_HDRTYPE_PPB: /* PCI-PCI bridge */
1859709f2afSjmcneill 		reg_start = PCI_MAPREG_START;
1869709f2afSjmcneill 		reg_end   = PCI_MAPREG_PPB_END;
1879709f2afSjmcneill 		break;
18835fd1a8bSdyoung 	case PCI_HDRTYPE_PCB: /* PCI-CardBus bridge */
1899709f2afSjmcneill 		reg_start = PCI_MAPREG_START;
1909709f2afSjmcneill 		reg_end   = PCI_MAPREG_PCB_END;
1919709f2afSjmcneill 		break;
1929709f2afSjmcneill 	}
1939709f2afSjmcneill 	error = useport = usemem = 0;
1949709f2afSjmcneill 
1959709f2afSjmcneill 	for (mapreg = reg_start; mapreg < reg_end; mapreg += width) {
1969709f2afSjmcneill 		/* inquire PCI device bus space requirement */
1979709f2afSjmcneill 		val = pci_conf_read(pc, tag, mapreg);
1989709f2afSjmcneill 		pci_conf_write(pc, tag, mapreg, ~0);
1999709f2afSjmcneill 
2009709f2afSjmcneill 		mask = pci_conf_read(pc, tag, mapreg);
2019709f2afSjmcneill 		pci_conf_write(pc, tag, mapreg, val);
2029709f2afSjmcneill 
2039709f2afSjmcneill 		type = PCI_MAPREG_TYPE(val);
2049709f2afSjmcneill 		width = 4;
2059709f2afSjmcneill 		if (type == PCI_MAPREG_TYPE_MEM) {
2069709f2afSjmcneill 			if (PCI_MAPREG_MEM_TYPE(val) ==
2079709f2afSjmcneill 			    PCI_MAPREG_MEM_TYPE_64BIT) {
2089709f2afSjmcneill 				/* XXX We could examine the upper 32 bits
2099709f2afSjmcneill 				 * XXX of the BAR here, but we are totally
2109709f2afSjmcneill 				 * XXX unprepared to handle a non-zero value,
2119709f2afSjmcneill 				 * XXX either here or anywhere else in
2129709f2afSjmcneill 				 * XXX i386-land.
2139709f2afSjmcneill 				 * XXX So just arrange to not look at the
2149709f2afSjmcneill 				 * XXX upper 32 bits, lest we misinterpret
2159709f2afSjmcneill 				 * XXX it as a 32-bit BAR set to zero.
2169709f2afSjmcneill 				 */
2179709f2afSjmcneill 			    width = 8;
2189709f2afSjmcneill 			}
2199709f2afSjmcneill 			size = PCI_MAPREG_MEM_SIZE(mask);
2209709f2afSjmcneill 		} else {
2219709f2afSjmcneill 			size = PCI_MAPREG_IO_SIZE(mask);
2229709f2afSjmcneill 		}
2239709f2afSjmcneill 		addr = pciaddr_ioaddr(val);
2249709f2afSjmcneill 
22535fd1a8bSdyoung 		if (size == 0) /* unused register */
2269709f2afSjmcneill 			continue;
2279709f2afSjmcneill 
2289709f2afSjmcneill 		if (type == PCI_MAPREG_TYPE_MEM)
2299709f2afSjmcneill 			++usemem;
2309709f2afSjmcneill 		else
2319709f2afSjmcneill 			++useport;
2329709f2afSjmcneill 
2339709f2afSjmcneill 		/* reservation/allocation phase */
2349709f2afSjmcneill 		error += (*func) (pc, tag, mapreg, ctx, type, &addr, size);
2359709f2afSjmcneill 
2369709f2afSjmcneill 		aprint_debug("\n\t%02xh %s 0x%08x 0x%08x",
2379709f2afSjmcneill 				mapreg, type ? "port" : "mem ",
2389709f2afSjmcneill 				(unsigned int)addr, (unsigned int)size);
2399709f2afSjmcneill 	}
2409709f2afSjmcneill 
2419709f2afSjmcneill 	/* enable/disable PCI device */
2429709f2afSjmcneill 	val = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
2439709f2afSjmcneill 	if (error == 0)
2449709f2afSjmcneill 		val |= (PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
2459709f2afSjmcneill 			PCI_COMMAND_MASTER_ENABLE);
2469709f2afSjmcneill 	else
2479709f2afSjmcneill 		val &= ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
2489709f2afSjmcneill 			 PCI_COMMAND_MASTER_ENABLE);
2499709f2afSjmcneill 	pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, val);
2509709f2afSjmcneill 
25135fd1a8bSdyoung 	if (error != 0)
2529709f2afSjmcneill 		pciaddr.nbogus++;
2539709f2afSjmcneill 
2549709f2afSjmcneill 	aprint_debug("\n\t\t[%s]\n", error ? "NG" : "OK");
2559709f2afSjmcneill }
2569709f2afSjmcneill 
25735fd1a8bSdyoung static int
pciaddr_do_resource_allocate(pci_chipset_tag_t pc,pcitag_t tag,int mapreg,void * ctx,int type,bus_addr_t * addr,bus_size_t size)2589709f2afSjmcneill pciaddr_do_resource_allocate(pci_chipset_tag_t pc, pcitag_t tag,
2599709f2afSjmcneill     int mapreg, void *ctx, int type, bus_addr_t *addr, bus_size_t size)
2609709f2afSjmcneill {
2619709f2afSjmcneill  	struct pciaddr *pciaddrmap = (struct pciaddr *)ctx;
2629709f2afSjmcneill 	bus_addr_t start;
2639709f2afSjmcneill 	int error;
2649709f2afSjmcneill  	struct extent *ex;
2659709f2afSjmcneill 
26635fd1a8bSdyoung 	if (*addr != 0) /* no need to allocate */
26735fd1a8bSdyoung 		return 0;
2689709f2afSjmcneill 
2699709f2afSjmcneill  	ex = (type == PCI_MAPREG_TYPE_MEM ?
2709709f2afSjmcneill  	      pciaddrmap->extent_mem : pciaddrmap->extent_port);
2719709f2afSjmcneill 
2729709f2afSjmcneill 	/* XXX Don't allocate if device is AGP device to avoid conflict. */
2739709f2afSjmcneill 	if (device_is_agp(pc, tag))
27435fd1a8bSdyoung 		return 0;
2759709f2afSjmcneill 
2769709f2afSjmcneill 	start = (type == PCI_MAPREG_TYPE_MEM ?
2779709f2afSjmcneill 		 pciaddrmap->mem_alloc_start : pciaddrmap->port_alloc_start);
2789709f2afSjmcneill 
2799709f2afSjmcneill 	if (start < ex->ex_start || start + size - 1 >= ex->ex_end) {
2809709f2afSjmcneill 		aprint_debug("No available resources. fixup failed\n");
28135fd1a8bSdyoung 		return 1;
2829709f2afSjmcneill 	}
2839709f2afSjmcneill 	error = extent_alloc_subregion(ex, start, ex->ex_end, size,
2849709f2afSjmcneill 				       size, 0,
285da702eb9Sjym 				       EX_FAST|EX_NOWAIT|EX_MALLOCOK,
286da702eb9Sjym 				       (u_long *)addr);
2879709f2afSjmcneill 	if (error) {
2889709f2afSjmcneill 		aprint_debug("No available resources. fixup failed\n");
28935fd1a8bSdyoung 		return 1;
2909709f2afSjmcneill 	}
2919709f2afSjmcneill 
2929709f2afSjmcneill 	/* write new address to PCI device configuration header */
2939709f2afSjmcneill 	pci_conf_write(pc, tag, mapreg, *addr);
2949709f2afSjmcneill 	/* check */
29535fd1a8bSdyoung 	aprint_debug("pci_addr_fixup: ");
2969709f2afSjmcneill 	pciaddr_print_devid(pc, tag);
2979709f2afSjmcneill 	if (pciaddr_ioaddr(pci_conf_read(pc, tag, mapreg)) != *addr) {
2989709f2afSjmcneill 		pci_conf_write(pc, tag, mapreg, 0); /* clear */
29960c3292cSjmcneill 		aprint_error("fixup failed. (new address=%#x)\n", (unsigned)*addr);
30035fd1a8bSdyoung 		return 1;
3019709f2afSjmcneill 	}
30235fd1a8bSdyoung 	aprint_debug("new address 0x%08x\n", (unsigned)*addr);
3039709f2afSjmcneill 
30435fd1a8bSdyoung 	return 0;
3059709f2afSjmcneill }
3069709f2afSjmcneill 
3079709f2afSjmcneill int
pciaddr_do_resource_reserve(pci_chipset_tag_t pc,pcitag_t tag,int mapreg,void * ctx,int type,bus_addr_t * addr,bus_size_t size)3089709f2afSjmcneill pciaddr_do_resource_reserve(pci_chipset_tag_t pc, pcitag_t tag,
3099709f2afSjmcneill     int mapreg, void *ctx, int type, bus_addr_t *addr, bus_size_t size)
3109709f2afSjmcneill {
3119709f2afSjmcneill 	struct extent *ex;
3129709f2afSjmcneill 	struct pciaddr *pciaddrmap = (struct pciaddr *)ctx;
3139709f2afSjmcneill 	int error;
3149709f2afSjmcneill 
3159709f2afSjmcneill 	if (*addr == 0)
31635fd1a8bSdyoung 		return 1;
3179709f2afSjmcneill 
3189709f2afSjmcneill 	ex = (type == PCI_MAPREG_TYPE_MEM ?
3199709f2afSjmcneill 	      pciaddrmap->extent_mem : pciaddrmap->extent_port);
3209709f2afSjmcneill 
3219709f2afSjmcneill 	error = extent_alloc_region(ex, *addr, size, EX_NOWAIT| EX_MALLOCOK);
3229709f2afSjmcneill 	if (error) {
3239709f2afSjmcneill 		aprint_debug("Resource conflict.\n");
3249709f2afSjmcneill 		pci_conf_write(pc, tag, mapreg, 0); /* clear */
32535fd1a8bSdyoung 		return 1;
3269709f2afSjmcneill 	}
3279709f2afSjmcneill 
32835fd1a8bSdyoung 	return 0;
3299709f2afSjmcneill }
3309709f2afSjmcneill 
3319709f2afSjmcneill bus_addr_t
pciaddr_ioaddr(uint32_t val)3329709f2afSjmcneill pciaddr_ioaddr(uint32_t val)
3339709f2afSjmcneill {
33435fd1a8bSdyoung 	return (PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM)
3359709f2afSjmcneill 		? PCI_MAPREG_MEM_ADDR(val)
33635fd1a8bSdyoung 		: PCI_MAPREG_IO_ADDR(val);
3379709f2afSjmcneill }
3389709f2afSjmcneill 
3399709f2afSjmcneill void
pciaddr_print_devid(pci_chipset_tag_t pc,pcitag_t tag)3409709f2afSjmcneill pciaddr_print_devid(pci_chipset_tag_t pc, pcitag_t tag)
3419709f2afSjmcneill {
3429709f2afSjmcneill 	int bus, device, function;
3439709f2afSjmcneill 	pcireg_t id;
3449709f2afSjmcneill 
3459709f2afSjmcneill 	id = pci_conf_read(pc, tag, PCI_ID_REG);
3469709f2afSjmcneill 	pci_decompose_tag(pc, tag, &bus, &device, &function);
34735fd1a8bSdyoung 	aprint_debug("%03d:%02d:%d 0x%04x 0x%04x ", bus, device, function,
3489709f2afSjmcneill 	       PCI_VENDOR(id), PCI_PRODUCT(id));
3499709f2afSjmcneill }
3509709f2afSjmcneill 
35135fd1a8bSdyoung static int
device_is_agp(pci_chipset_tag_t pc,pcitag_t tag)3529709f2afSjmcneill device_is_agp(pci_chipset_tag_t pc, pcitag_t tag)
3539709f2afSjmcneill {
3549709f2afSjmcneill 	pcireg_t class, status, rval;
3559709f2afSjmcneill 	int off;
3569709f2afSjmcneill 
3579709f2afSjmcneill 	/* Check AGP device. */
3589709f2afSjmcneill 	class = pci_conf_read(pc, tag, PCI_CLASS_REG);
3599709f2afSjmcneill 	if (PCI_CLASS(class) == PCI_CLASS_DISPLAY) {
3609709f2afSjmcneill 		status = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG);
3619709f2afSjmcneill 		if (status & PCI_STATUS_CAPLIST_SUPPORT) {
3629709f2afSjmcneill 			rval = pci_conf_read(pc, tag, PCI_CAPLISTPTR_REG);
3639709f2afSjmcneill 			for (off = PCI_CAPLIST_PTR(rval);
3649709f2afSjmcneill 			    off != 0;
3659709f2afSjmcneill 			    off = PCI_CAPLIST_NEXT(rval) ) {
3669709f2afSjmcneill 				rval = pci_conf_read(pc, tag, off);
3679709f2afSjmcneill 				if (PCI_CAPLIST_CAP(rval) == PCI_CAP_AGP)
36835fd1a8bSdyoung 					return 1;
3699709f2afSjmcneill 			}
3709709f2afSjmcneill 		}
3719709f2afSjmcneill 	}
37235fd1a8bSdyoung 	return 0;
3739709f2afSjmcneill }
374