root/arch/i386/pci/pcibios.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcibiosprobe
  2. pcibiosattach
  3. pcibios_pir_init
  4. pcibios_get_status
  5. pcibios_get_intr_routing
  6. pcibios_return_code
  7. pcibios_print_exclirq
  8. pcibios_print_pir_table
  9. pci_device_foreach

    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 }

/* [<][>][^][v][top][bottom][index][help] */