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