root/arch/i386/pci/pci_bus_fixup.c

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

DEFINITIONS

This source file includes following definitions.
  1. pci_bus_check
  2. pci_bus_assign
  3. pci_bus_fixup
  4. pcibus_print_devid

    1 /*      $OpenBSD: pci_bus_fixup.c,v 1.9 2006/08/18 22:18:18 kettenis Exp $      */
    2 /*      $NetBSD: pci_bus_fixup.c,v 1.1 1999/11/17 07:32:58 thorpej Exp $  */
    3 
    4 /*
    5  * Copyright (c) 1999, by UCHIYAMA Yasushi
    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. The name of the developer may NOT be used to endorse or promote products
   14  *    derived from this software without specific prior written permission.
   15  * 
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
   26  * SUCH DAMAGE. 
   27  */
   28 
   29 /*
   30  * PCI bus renumbering support.
   31  */
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/device.h>
   37 
   38 #include <machine/bus.h>
   39 
   40 #include <dev/pci/pcireg.h>
   41 #include <dev/pci/pcivar.h>
   42 #include <dev/pci/pcidevs.h>
   43 #include <dev/pci/ppbreg.h>
   44 
   45 #include <i386/pci/pcibiosvar.h>
   46 
   47 int     pci_bus_check(pci_chipset_tag_t, int);
   48 int     pci_bus_assign(pci_chipset_tag_t, int);
   49 void    pcibus_print_devid(pci_chipset_tag_t, pcitag_t);
   50 
   51 int
   52 pci_bus_check(pci_chipset_tag_t pc, int bus)
   53 {
   54         int device, maxdevs, function, nfuncs, bus_max, bus_sub;
   55         const struct pci_quirkdata *qd;
   56         pcireg_t reg;
   57         pcitag_t tag;
   58 
   59         bus_max = bus;
   60 
   61         maxdevs = pci_bus_maxdevs(pc, bus);
   62         for (device = 0; device < maxdevs; device++) {
   63                 tag = pci_make_tag(pc, bus, device, 0);
   64                 reg = pci_conf_read(pc, tag, PCI_ID_REG);
   65 
   66                 /* can't be that many */
   67                 if (bus_max == 255)
   68                         break;
   69 
   70                 /* Invalid vendor ID value? */
   71                 if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
   72                         continue;
   73                 /* XXX Not invalid, but we've done this ~forever. */
   74                 if (PCI_VENDOR(reg) == 0)
   75                         continue;
   76 
   77                 qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg));
   78 
   79                 reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
   80                 if (PCI_HDRTYPE_MULTIFN(reg) ||
   81                     (qd != NULL &&
   82                      (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
   83                         nfuncs = 8;
   84                 else
   85                         nfuncs = 1;
   86 
   87                 for (function = 0; function < nfuncs; function++) {
   88                         tag = pci_make_tag(pc, bus, device, function);
   89                         reg = pci_conf_read(pc, tag, PCI_ID_REG);
   90 
   91                         /* Invalid vendor ID value? */
   92                         if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
   93                                 continue;
   94                         /* XXX Not invalid, but we've done this ~forever. */
   95                         if (PCI_VENDOR(reg) == 0)
   96                                 continue;
   97 
   98                         reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
   99                         if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
  100                             (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI ||
  101                              PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
  102 
  103                                 reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
  104                                 if (PPB_BUSINFO_PRIMARY(reg) != bus) {
  105                                         if (pcibios_flags & PCIBIOS_VERBOSE) {
  106                                                 pcibus_print_devid(pc, tag);
  107                                                 printf("Mismatched primary bus: "
  108                                                     "primary %d, secondary %d, "
  109                                                     "subordinate %d\n",
  110                                                     PPB_BUSINFO_PRIMARY(reg),
  111                                                     PPB_BUSINFO_SECONDARY(reg),
  112                                                     PPB_BUSINFO_SUBORDINATE(reg));
  113                                         }
  114                                         return (-1);
  115                                 }
  116                                 if (PPB_BUSINFO_SECONDARY(reg) <= bus) {
  117                                         if (pcibios_flags & PCIBIOS_VERBOSE) {
  118                                                 pcibus_print_devid(pc, tag);
  119                                                 printf("Incorrect secondary bus: "
  120                                                     "primary %d, secondary %d, "
  121                                                     "subordinate %d\n",
  122                                                     PPB_BUSINFO_PRIMARY(reg),
  123                                                     PPB_BUSINFO_SECONDARY(reg),
  124                                                     PPB_BUSINFO_SUBORDINATE(reg));
  125                                         }
  126                                         return (-1);
  127                                 }
  128 
  129                                 /* Scan subordinate bus. */
  130                                 bus_sub = pci_bus_check(pc,
  131                                     PPB_BUSINFO_SECONDARY(reg));
  132                                 if (bus_sub == -1)
  133                                         return (-1);
  134 
  135                                 if (PPB_BUSINFO_SUBORDINATE(reg) < bus_sub) {
  136                                         if (pcibios_flags & PCIBIOS_VERBOSE) {
  137                                                 pcibus_print_devid(pc, tag);
  138                                                 printf("Incorrect subordinate bus %d: "
  139                                                     "primary %d, secondary %d, "
  140                                                     "subordinate %d\n", bus_sub,
  141                                                     PPB_BUSINFO_PRIMARY(reg),
  142                                                     PPB_BUSINFO_SECONDARY(reg),
  143                                                     PPB_BUSINFO_SUBORDINATE(reg));
  144                                         }
  145                                         return (-1);
  146                                 }
  147 
  148                                 bus_max = (bus_sub > bus_max) ?
  149                                     bus_sub : bus_max;
  150                         }
  151                 }
  152         }
  153 
  154         return (bus_max);       /* last # of subordinate bus */
  155 }
  156 
  157 int
  158 pci_bus_assign(pci_chipset_tag_t pc, int bus)
  159 {
  160         static int bridge_cnt;
  161         int bridge, device, maxdevs, function, nfuncs, bus_max, bus_sub;
  162         const struct pci_quirkdata *qd;
  163         pcireg_t reg;
  164         pcitag_t tag;
  165 
  166         bus_max = bus;
  167 
  168         maxdevs = pci_bus_maxdevs(pc, bus);
  169         for (device = 0; device < maxdevs; device++) {
  170                 tag = pci_make_tag(pc, bus, device, 0);
  171                 reg = pci_conf_read(pc, tag, PCI_ID_REG);
  172 
  173                 /* can't be that many */
  174                 if (bus_max == 255)
  175                         break;
  176 
  177                 /* Invalid vendor ID value? */
  178                 if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
  179                         continue;
  180                 /* XXX Not invalid, but we've done this ~forever. */
  181                 if (PCI_VENDOR(reg) == 0)
  182                         continue;
  183 
  184                 qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg));
  185 
  186                 reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
  187                 if (PCI_HDRTYPE_MULTIFN(reg) ||
  188                     (qd != NULL &&
  189                      (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0))
  190                         nfuncs = 8;
  191                 else
  192                         nfuncs = 1;
  193 
  194                 for (function = 0; function < nfuncs; function++) {
  195                         tag = pci_make_tag(pc, bus, device, function);
  196                         reg = pci_conf_read(pc, tag, PCI_ID_REG);
  197 
  198                         /* Invalid vendor ID value? */
  199                         if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
  200                                 continue;
  201                         /* XXX Not invalid, but we've done this ~forever. */
  202                         if (PCI_VENDOR(reg) == 0)
  203                                 continue;
  204 
  205                         reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
  206                         if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
  207                             (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI ||
  208                              PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
  209                                 /* Assign the bridge's secondary bus #. */
  210                                 bus_max++;
  211 
  212                                 reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
  213                                 reg &= 0xff000000;
  214                                 reg |= bus | (bus_max << 8) | (0xff << 16);
  215                                 pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg);
  216 
  217                                 /* Scan subordinate bus. */
  218                                 bus_sub = pci_bus_assign(pc, bus_max);
  219 
  220                                 /* Configure the bridge. */
  221                                 reg &= 0xff000000;
  222                                 reg |= bus | (bus_max << 8) | (bus_sub << 16);
  223                                 pci_conf_write(pc, tag, PPB_REG_BUSINFO, reg);
  224 
  225                                 if (pcibios_flags & PCIBIOS_VERBOSE) {
  226                                         /* Assign the bridge #. */
  227                                         bridge = bridge_cnt++;
  228 
  229                                         printf("PCI bridge %d: primary %d, "
  230                                             "secondary %d, subordinate %d\n",
  231                                             bridge, bus, bus_max, bus_sub);
  232                                 }
  233 
  234                                 /* Next bridge's secondary bus #. */
  235                                 bus_max = (bus_sub > bus_max) ?
  236                                     bus_sub : bus_max;
  237                         }
  238                 }
  239         }
  240 
  241         return (bus_max);       /* last # of subordinate bus */
  242 }
  243 
  244 int
  245 pci_bus_fixup(pci_chipset_tag_t pc, int bus)
  246 {
  247         int bus_max;
  248 
  249         bus_max = pci_bus_check(pc, bus);
  250         if (bus_max != -1)
  251                 return (bus_max);
  252 
  253         if (pcibios_flags & PCIBIOS_VERBOSE)
  254                 printf("PCI bus renumbering needed\n");
  255         return pci_bus_assign(pc, bus);
  256 }
  257 
  258 void
  259 pcibus_print_devid(pci_chipset_tag_t pc, pcitag_t tag)
  260 {
  261         int bus, device, function;      
  262         pcireg_t id;
  263 
  264         id = pci_conf_read(pc, tag, PCI_ID_REG);
  265         pci_decompose_tag(pc, tag, &bus, &device, &function);
  266         printf("%03d:%02d:%d %04x:%04x\n", bus, device, function, 
  267                PCI_VENDOR(id), PCI_PRODUCT(id));
  268 }

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