Annotation of sys/arch/i386/pci/pcibios.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pcibios.c,v 1.37 2007/03/19 05:32:05 deraadt Exp $ */
! 2: /* $NetBSD: pcibios.c,v 1.5 2000/08/01 05:23:59 uch Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2000 Michael Shalayeff
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 20: * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
! 21: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
! 22: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! 23: * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 24: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
! 25: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
! 26: * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! 27: * THE POSSIBILITY OF SUCH DAMAGE.
! 28: */
! 29: /*-
! 30: * Copyright (c) 1999 The NetBSD Foundation, Inc.
! 31: * All rights reserved.
! 32: *
! 33: * This code is derived from software contributed to The NetBSD Foundation
! 34: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
! 35: * NASA Ames Research Center.
! 36: *
! 37: * Redistribution and use in source and binary forms, with or without
! 38: * modification, are permitted provided that the following conditions
! 39: * are met:
! 40: * 1. Redistributions of source code must retain the above copyright
! 41: * notice, this list of conditions and the following disclaimer.
! 42: * 2. Redistributions in binary form must reproduce the above copyright
! 43: * notice, this list of conditions and the following disclaimer in the
! 44: * documentation and/or other materials provided with the distribution.
! 45: * 3. All advertising materials mentioning features or use of this software
! 46: * must display the following acknowledgement:
! 47: * This product includes software developed by the NetBSD
! 48: * Foundation, Inc. and its contributors.
! 49: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 50: * contributors may be used to endorse or promote products derived
! 51: * from this software without specific prior written permission.
! 52: *
! 53: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 54: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 55: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 56: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 57: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 58: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 59: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 60: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 61: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 62: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 63: * POSSIBILITY OF SUCH DAMAGE.
! 64: */
! 65: /*
! 66: * Copyright (c) 1999, by UCHIYAMA Yasushi
! 67: * All rights reserved.
! 68: *
! 69: * Redistribution and use in source and binary forms, with or without
! 70: * modification, are permitted provided that the following conditions
! 71: * are met:
! 72: * 1. Redistributions of source code must retain the above copyright
! 73: * notice, this list of conditions and the following disclaimer.
! 74: * 2. The name of the developer may NOT be used to endorse or promote products
! 75: * derived from this software without specific prior written permission.
! 76: *
! 77: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 78: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 79: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 80: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 81: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 82: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 83: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 84: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 85: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 86: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 87: * SUCH DAMAGE.
! 88: */
! 89:
! 90: /*
! 91: * Interface to the PCI BIOS and PCI Interrupt Routing table.
! 92: */
! 93:
! 94: #include <sys/param.h>
! 95: #include <sys/systm.h>
! 96: #include <sys/device.h>
! 97: #include <sys/malloc.h>
! 98:
! 99: #include <dev/isa/isareg.h>
! 100: #include <i386/isa/isa_machdep.h>
! 101:
! 102: #include <dev/pci/pcireg.h>
! 103: #include <dev/pci/pcivar.h>
! 104: #include <dev/pci/pcidevs.h>
! 105:
! 106: #include <i386/pci/pcibiosvar.h>
! 107:
! 108: #include <machine/biosvar.h>
! 109:
! 110: int pcibios_flags;
! 111: int pcibios_present;
! 112:
! 113: struct pcibios_pir_header pcibios_pir_header;
! 114: struct pcibios_intr_routing *pcibios_pir_table;
! 115: int pcibios_pir_table_nentries;
! 116: int pcibios_flags = 0;
! 117:
! 118: struct bios32_entry pcibios_entry;
! 119: struct bios32_entry_info pcibios_entry_info;
! 120:
! 121: struct pcibios_intr_routing *pcibios_pir_init(struct pcibios_softc *);
! 122:
! 123: int pcibios_get_status(struct pcibios_softc *,
! 124: u_int32_t *, u_int32_t *, u_int32_t *,
! 125: u_int32_t *, u_int32_t *, u_int32_t *, u_int32_t *);
! 126: int pcibios_get_intr_routing(struct pcibios_softc *,
! 127: struct pcibios_intr_routing *, int *, u_int16_t *);
! 128:
! 129: int pcibios_return_code(struct pcibios_softc *, u_int16_t, const char *);
! 130:
! 131: void pcibios_print_exclirq(struct pcibios_softc *);
! 132: void pcibios_print_pir_table(void);
! 133:
! 134: #define PCI_IRQ_TABLE_START 0xf0000
! 135: #define PCI_IRQ_TABLE_END 0xfffff
! 136:
! 137: struct cfdriver pcibios_cd = {
! 138: NULL, "pcibios", DV_DULL
! 139: };
! 140:
! 141: int pcibiosprobe(struct device *, void *, void *);
! 142: void pcibiosattach(struct device *, struct device *, void *);
! 143:
! 144: struct cfattach pcibios_ca = {
! 145: sizeof(struct pcibios_softc), pcibiosprobe, pcibiosattach
! 146: };
! 147:
! 148: int
! 149: pcibiosprobe(struct device *parent, void *match, void *aux)
! 150: {
! 151: struct bios_attach_args *ba = aux;
! 152: u_int32_t rev_maj, rev_min, mech1, mech2, scmech1, scmech2, maxbus;
! 153: int rv;
! 154:
! 155: if (strcmp(ba->bios_dev, "pcibios"))
! 156: return 0;
! 157:
! 158: rv = bios32_service(PCIBIOS_SIGNATURE, &pcibios_entry,
! 159: &pcibios_entry_info);
! 160:
! 161: PCIBIOS_PRINTV(("pcibiosprobe: 0x%lx:0x%lx at 0x%lx[0x%lx]\n",
! 162: pcibios_entry.segment, pcibios_entry.offset,
! 163: pcibios_entry_info.bei_base, pcibios_entry_info.bei_size));
! 164:
! 165: return rv &&
! 166: pcibios_get_status(NULL, &rev_maj, &rev_min, &mech1, &mech2,
! 167: &scmech1, &scmech2, &maxbus) == PCIBIOS_SUCCESS;
! 168: }
! 169:
! 170: void
! 171: pcibiosattach(struct device *parent, struct device *self, void *aux)
! 172: {
! 173: struct pcibios_softc *sc = (struct pcibios_softc *)self;
! 174: u_int32_t rev_maj, rev_min, mech1, mech2, scmech1, scmech2;
! 175:
! 176: pcibios_flags = sc->sc_dev.dv_cfdata->cf_flags;
! 177:
! 178: pcibios_get_status((struct pcibios_softc *)self, &rev_maj,
! 179: &rev_min, &mech1, &mech2,
! 180: &scmech1, &scmech2, &sc->max_bus);
! 181:
! 182: printf(": rev %d.%d @ 0x%lx/0x%lx\n",
! 183: rev_maj, rev_min >> 4, pcibios_entry_info.bei_base,
! 184: pcibios_entry_info.bei_size);
! 185:
! 186: PCIBIOS_PRINTV(("%s: config mechanism %s%s, special cycles %s%s, "
! 187: "last bus %d\n", sc->sc_dev.dv_xname,
! 188: mech1 ? "[1]" : "[x]", mech2 ? "[2]" : "[x]",
! 189: scmech1 ? "[1]" : "[x]", scmech2 ? "[2]" : "[x]", sc->max_bus));
! 190:
! 191: /*
! 192: * The PCI BIOS tells us the config mechanism; fill it in now
! 193: * so that pci_mode_detect() doesn't have to look for it.
! 194: */
! 195: pci_mode = mech1 ? 1 : 2;
! 196:
! 197: pcibios_present = 1;
! 198:
! 199: /*
! 200: * Find the PCI IRQ Routing table.
! 201: */
! 202:
! 203: if (!(pcibios_flags & PCIBIOS_INTR_FIXUP) &&
! 204: pcibios_pir_init((struct pcibios_softc *)self) != NULL) {
! 205: int rv;
! 206:
! 207: /*
! 208: * Fixup interrupt routing.
! 209: */
! 210: rv = pci_intr_fixup(sc, NULL, I386_BUS_SPACE_IO);
! 211: switch (rv) {
! 212: case -1:
! 213: /* Non-fatal error. */
! 214: printf("%s: Warning, unable to fix up PCI interrupt "
! 215: "routing\n", sc->sc_dev.dv_xname);
! 216: break;
! 217:
! 218: case 1:
! 219: /* Fatal error. */
! 220: printf("%s: interrupt fixup failed\n", sc->sc_dev.dv_xname);
! 221: return;
! 222: }
! 223:
! 224: /*
! 225: * XXX Clear `pciirq' from the ISA interrupt allocation
! 226: * XXX mask.
! 227: */
! 228: }
! 229:
! 230: if (!(pcibios_flags & PCIBIOS_BUS_FIXUP)) {
! 231: sc->max_bus = pci_bus_fixup(NULL, 0);
! 232: printf("%s: PCI bus #%d is the last bus\n",
! 233: sc->sc_dev.dv_xname, sc->max_bus);
! 234: }
! 235:
! 236: if (!(pcibios_flags & PCIBIOS_ADDR_FIXUP))
! 237: pci_addr_fixup(sc, NULL, sc->max_bus);
! 238: }
! 239:
! 240: struct pcibios_intr_routing *
! 241: pcibios_pir_init(struct pcibios_softc *sc)
! 242: {
! 243: paddr_t pa;
! 244:
! 245: pcibios_pir_table = NULL;
! 246: for (pa = PCI_IRQ_TABLE_START; pa < PCI_IRQ_TABLE_END; pa += 16) {
! 247: u_int8_t *p, cksum;
! 248: struct pcibios_pir_header *pirh;
! 249: int i;
! 250:
! 251: p = ISA_HOLE_VADDR(pa);
! 252: pirh = (struct pcibios_pir_header *)p;
! 253: /*
! 254: * Some laptops (such as the Toshiba Libretto L series)
! 255: * use _PIR instead of the standard $PIR for the signature
! 256: * so we check for that too.
! 257: */
! 258: if (pirh->signature != BIOS32_MAKESIG('$', 'P', 'I', 'R') &&
! 259: pirh->signature != BIOS32_MAKESIG('_', 'P', 'I', 'R'))
! 260: continue;
! 261:
! 262: if (pirh->tablesize < sizeof(*pirh))
! 263: continue;
! 264:
! 265: cksum = 0;
! 266: for (i = 0; i < pirh->tablesize; i++)
! 267: cksum += p[i];
! 268:
! 269: printf("%s: PCI IRQ Routing Table rev %d.%d @ 0x%lx/%d "
! 270: "(%d entries)\n", sc->sc_dev.dv_xname,
! 271: pirh->version >> 8, pirh->version & 0xff, pa,
! 272: pirh->tablesize, (pirh->tablesize - sizeof(*pirh)) / 16);
! 273:
! 274: if (cksum != 0) {
! 275: printf("%s: bad IRQ table checksum\n",
! 276: sc->sc_dev.dv_xname);
! 277: continue;
! 278: }
! 279:
! 280: if (pirh->tablesize % 16 != 0) {
! 281: printf("%s: bad IRQ table size\n", sc->sc_dev.dv_xname);
! 282: continue;
! 283: }
! 284:
! 285: if (pirh->version != 0x0100) {
! 286: printf("%s: unsupported IRQ table version\n",
! 287: sc->sc_dev.dv_xname);
! 288: continue;
! 289: }
! 290:
! 291: /*
! 292: * We can handle this table! Make a copy of it.
! 293: */
! 294: pcibios_pir_header = *pirh;
! 295: pcibios_pir_table =
! 296: malloc(pirh->tablesize - sizeof(*pirh), M_DEVBUF, M_NOWAIT);
! 297: if (pcibios_pir_table == NULL) {
! 298: printf("%s: no memory for $PIR\n", sc->sc_dev.dv_xname);
! 299: return NULL;
! 300: }
! 301: bcopy(p + sizeof(*pirh), pcibios_pir_table,
! 302: pirh->tablesize - sizeof(*pirh));
! 303: pcibios_pir_table_nentries =
! 304: (pirh->tablesize - sizeof(*pirh)) / 16;
! 305:
! 306: }
! 307:
! 308: /*
! 309: * If there was no PIR table found, try using the PCI BIOS
! 310: * Get Interrupt Routing call.
! 311: *
! 312: * XXX The interface to this call sucks; just allocate enough
! 313: * XXX room for 32 entries.
! 314: */
! 315: if (pcibios_pir_table == NULL) {
! 316:
! 317: pcibios_pir_table_nentries = 32;
! 318: pcibios_pir_table = malloc(pcibios_pir_table_nentries *
! 319: sizeof(*pcibios_pir_table), M_DEVBUF, M_NOWAIT);
! 320: if (pcibios_pir_table == NULL) {
! 321: printf("%s: no memory for $PIR\n", sc->sc_dev.dv_xname);
! 322: return NULL;
! 323: }
! 324: if (pcibios_get_intr_routing(sc, pcibios_pir_table,
! 325: &pcibios_pir_table_nentries,
! 326: &pcibios_pir_header.exclusive_irq) != PCIBIOS_SUCCESS) {
! 327: printf("%s: PCI IRQ Routing information unavailable.\n",
! 328: sc->sc_dev.dv_xname);
! 329: free(pcibios_pir_table, M_DEVBUF);
! 330: pcibios_pir_table = NULL;
! 331: pcibios_pir_table_nentries = 0;
! 332: return NULL;
! 333: }
! 334: printf("%s: PCI BIOS has %d Interrupt Routing table entries\n",
! 335: sc->sc_dev.dv_xname, pcibios_pir_table_nentries);
! 336: }
! 337:
! 338: pcibios_print_exclirq(sc);
! 339: if (pcibios_flags & PCIBIOS_INTRDEBUG)
! 340: pcibios_print_pir_table();
! 341: return pcibios_pir_table;
! 342: }
! 343:
! 344: int
! 345: pcibios_get_status(struct pcibios_softc *sc, u_int32_t *rev_maj,
! 346: u_int32_t *rev_min, u_int32_t *mech1, u_int32_t *mech2, u_int32_t *scmech1,
! 347: u_int32_t *scmech2, u_int32_t *maxbus)
! 348: {
! 349: u_int32_t ax, bx, cx, edx;
! 350: int rv;
! 351:
! 352: __asm __volatile("pushl %%es\n\t"
! 353: "pushl %%ds\n\t"
! 354: "movw 4(%%edi), %%cx\n\t"
! 355: "movl %%ecx, %%ds\n\t"
! 356: "lcall %%cs:*(%%edi)\n\t"
! 357: "pop %%ds\n\t"
! 358: "pop %%es\n\t"
! 359: "jc 1f\n\t"
! 360: "xor %%ah, %%ah\n"
! 361: "1:"
! 362: : "=a" (ax), "=b" (bx), "=c" (cx), "=d" (edx)
! 363: : "0" (0xb101), "D" (&pcibios_entry)
! 364: : "cc", "memory");
! 365:
! 366: rv = pcibios_return_code(sc, ax, "pcibios_get_status");
! 367: if (rv != PCIBIOS_SUCCESS)
! 368: return (rv);
! 369:
! 370: if (edx != BIOS32_MAKESIG('P', 'C', 'I', ' '))
! 371: return (PCIBIOS_SERVICE_NOT_PRESENT); /* XXX */
! 372:
! 373: /*
! 374: * Fill in the various pieces of info we're looking for.
! 375: */
! 376: *mech1 = ax & 1;
! 377: *mech2 = ax & (1 << 1);
! 378: *scmech1 = ax & (1 << 4);
! 379: *scmech2 = ax & (1 << 5);
! 380: *rev_maj = (bx >> 8) & 0xff;
! 381: *rev_min = bx & 0xff;
! 382: *maxbus = cx & 0xff;
! 383:
! 384: return (PCIBIOS_SUCCESS);
! 385: }
! 386:
! 387: int
! 388: pcibios_get_intr_routing(struct pcibios_softc *sc,
! 389: struct pcibios_intr_routing *table, int *nentries, u_int16_t *exclirq)
! 390: {
! 391: u_int32_t ax, bx;
! 392: int rv;
! 393: struct {
! 394: u_int16_t size;
! 395: u_int32_t offset;
! 396: u_int16_t segment;
! 397: } __attribute__((__packed__)) args;
! 398:
! 399: args.size = *nentries * sizeof(*table);
! 400: args.offset = (u_int32_t)table;
! 401: args.segment = GSEL(GDATA_SEL, SEL_KPL);
! 402:
! 403: memset(table, 0, args.size);
! 404:
! 405: __asm __volatile("pushl %%es\n\t"
! 406: "pushl %%ds\n\t"
! 407: "movw 4(%%esi), %%cx\n\t"
! 408: "movl %%ecx, %%ds\n\t"
! 409: "lcall %%cs:*(%%esi)\n\t"
! 410: "popl %%ds\n\t"
! 411: "popl %%es\n\t"
! 412: "jc 1f\n\t"
! 413: "xor %%ah, %%ah\n"
! 414: "1:\n"
! 415: : "=a" (ax), "=b" (bx)
! 416: : "0" (0xb10e), "1" (0), "D" (&args), "S" (&pcibios_entry)
! 417: : "%ecx", "%edx", "cc", "memory");
! 418:
! 419: rv = pcibios_return_code(sc, ax, "pcibios_get_intr_routing");
! 420: if (rv != PCIBIOS_SUCCESS)
! 421: return (rv);
! 422:
! 423: *nentries = args.size / sizeof(*table);
! 424: *exclirq |= bx;
! 425:
! 426: return (PCIBIOS_SUCCESS);
! 427: }
! 428:
! 429: int
! 430: pcibios_return_code(struct pcibios_softc *sc, u_int16_t ax, const char *func)
! 431: {
! 432: const char *errstr;
! 433: int rv = ax >> 8;
! 434: char *nam;
! 435:
! 436: if (sc)
! 437: nam = sc->sc_dev.dv_xname;
! 438: else
! 439: nam = "pcibios0";
! 440:
! 441: switch (rv) {
! 442: case PCIBIOS_SUCCESS:
! 443: return (PCIBIOS_SUCCESS);
! 444:
! 445: case PCIBIOS_SERVICE_NOT_PRESENT:
! 446: errstr = "service not present";
! 447: break;
! 448:
! 449: case PCIBIOS_FUNCTION_NOT_SUPPORTED:
! 450: errstr = "function not supported";
! 451: break;
! 452:
! 453: case PCIBIOS_BAD_VENDOR_ID:
! 454: errstr = "bad vendor ID";
! 455: break;
! 456:
! 457: case PCIBIOS_DEVICE_NOT_FOUND:
! 458: errstr = "device not found";
! 459: break;
! 460:
! 461: case PCIBIOS_BAD_REGISTER_NUMBER:
! 462: errstr = "bad register number";
! 463: break;
! 464:
! 465: case PCIBIOS_SET_FAILED:
! 466: errstr = "set failed";
! 467: break;
! 468:
! 469: case PCIBIOS_BUFFER_TOO_SMALL:
! 470: errstr = "buffer too small";
! 471: break;
! 472:
! 473: default:
! 474: printf("%s: %s - unknown return code 0x%x\n",
! 475: nam, func, rv);
! 476: return (rv);
! 477: }
! 478:
! 479: printf("%s: %s - %s\n", nam, func, errstr);
! 480: return (rv);
! 481: }
! 482:
! 483: void
! 484: pcibios_print_exclirq(struct pcibios_softc *sc)
! 485: {
! 486: int i;
! 487:
! 488: if (pcibios_pir_header.exclusive_irq) {
! 489: printf("%s: PCI Exclusive IRQs:", sc->sc_dev.dv_xname);
! 490: for (i = 0; i < 16; i++) {
! 491: if (pcibios_pir_header.exclusive_irq & (1 << i))
! 492: printf(" %d", i);
! 493: }
! 494: printf("\n");
! 495: }
! 496: }
! 497:
! 498: void
! 499: pcibios_print_pir_table(void)
! 500: {
! 501: int i, j;
! 502:
! 503: for (i = 0; i < pcibios_pir_table_nentries; i++) {
! 504: printf("PIR Entry %d:\n", i);
! 505: printf("\tBus: %d Device: %d\n",
! 506: pcibios_pir_table[i].bus,
! 507: PIR_DEVFUNC_DEVICE(pcibios_pir_table[i].device));
! 508: for (j = 0; j < 4; j++) {
! 509: printf("\t\tINT%c: link 0x%02x bitmap 0x%04x\n",
! 510: 'A' + j,
! 511: pcibios_pir_table[i].linkmap[j].link,
! 512: pcibios_pir_table[i].linkmap[j].bitmap);
! 513: }
! 514: }
! 515: }
! 516:
! 517: void
! 518: pci_device_foreach(struct pcibios_softc *sc, pci_chipset_tag_t pc, int maxbus,
! 519: void (*func)(struct pcibios_softc *, pci_chipset_tag_t, pcitag_t))
! 520: {
! 521: const struct pci_quirkdata *qd;
! 522: int bus, device, function, maxdevs, nfuncs;
! 523: pcireg_t id, bhlcr;
! 524: pcitag_t tag;
! 525:
! 526: for (bus = 0; bus <= maxbus; bus++) {
! 527: maxdevs = pci_bus_maxdevs(pc, bus);
! 528: for (device = 0; device < maxdevs; device++) {
! 529: tag = pci_make_tag(pc, bus, device, 0);
! 530: id = pci_conf_read(pc, tag, PCI_ID_REG);
! 531:
! 532: /* Invalid vendor ID value? */
! 533: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
! 534: continue;
! 535: /* XXX Not invalid, but we've done this ~forever. */
! 536: if (PCI_VENDOR(id) == 0)
! 537: continue;
! 538:
! 539: qd = pci_lookup_quirkdata(PCI_VENDOR(id),
! 540: PCI_PRODUCT(id));
! 541:
! 542: bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
! 543: if (PCI_HDRTYPE_MULTIFN(bhlcr) ||
! 544: (qd != NULL &&
! 545: (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
! 546: nfuncs = 8;
! 547: else
! 548: nfuncs = 1;
! 549:
! 550: for (function = 0; function < nfuncs; function++) {
! 551: tag = pci_make_tag(pc, bus, device, function);
! 552: id = pci_conf_read(pc, tag, PCI_ID_REG);
! 553:
! 554: /* Invalid vendor ID value? */
! 555: if (PCI_VENDOR(id) == PCI_VENDOR_INVALID)
! 556: continue;
! 557: /*
! 558: * XXX Not invalid, but we've done this
! 559: * ~forever.
! 560: */
! 561: if (PCI_VENDOR(id) == 0)
! 562: continue;
! 563: (*func)(sc, pc, tag);
! 564: }
! 565: }
! 566: }
! 567: }
CVSweb