The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/amd64/pci/pci_bus.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include "opt_cpu.h"
   31 
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/bus.h>
   35 #include <sys/kernel.h>
   36 #include <sys/malloc.h>
   37 #include <sys/module.h>
   38 
   39 #include <dev/pci/pcivar.h>
   40 #include <dev/pci/pcireg.h>
   41 #include <dev/pci/pcib_private.h>
   42 #include <isa/isavar.h>
   43 #include <machine/legacyvar.h>
   44 #include <machine/pci_cfgreg.h>
   45 
   46 #include "pcib_if.h"
   47 
   48 int
   49 legacy_pcib_maxslots(device_t dev)
   50 {
   51         return 31;
   52 }
   53 
   54 /* read configuration space register */
   55 
   56 u_int32_t
   57 legacy_pcib_read_config(device_t dev, int bus, int slot, int func,
   58                         int reg, int bytes)
   59 {
   60         return(pci_cfgregread(bus, slot, func, reg, bytes));
   61 }
   62 
   63 /* write configuration space register */
   64 
   65 void
   66 legacy_pcib_write_config(device_t dev, int bus, int slot, int func,
   67                          int reg, u_int32_t data, int bytes)
   68 {
   69         pci_cfgregwrite(bus, slot, func, reg, data, bytes);
   70 }
   71 
   72 /* route interrupt */
   73 
   74 static int
   75 legacy_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
   76 {
   77 
   78         /* No routing possible */
   79         return (PCI_INVALID_IRQ);
   80 }
   81 
   82 static const char *
   83 legacy_pcib_is_host_bridge(int bus, int slot, int func,
   84                           uint32_t id, uint8_t class, uint8_t subclass,
   85                           uint8_t *busnum)
   86 {
   87         const char *s = NULL;
   88 
   89         *busnum = 0;
   90         if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST)
   91                 s = "Host to PCI bridge";
   92         return s;
   93 }
   94 
   95 /*
   96  * Scan the first pci bus for host-pci bridges and add pcib instances
   97  * to the nexus for each bridge.
   98  */
   99 static void
  100 legacy_pcib_identify(driver_t *driver, device_t parent)
  101 {
  102         int bus, slot, func;
  103         u_int8_t  hdrtype;
  104         int found = 0;
  105         int pcifunchigh;
  106         int found824xx = 0;
  107         int found_orion = 0;
  108         device_t child;
  109         devclass_t pci_devclass;
  110 
  111         if (pci_cfgregopen() == 0)
  112                 return;
  113         /*
  114          * Check to see if we haven't already had a PCI bus added
  115          * via some other means.  If we have, bail since otherwise
  116          * we're going to end up duplicating it.
  117          */
  118         if ((pci_devclass = devclass_find("pci")) &&
  119                 devclass_get_device(pci_devclass, 0))
  120                 return;
  121 
  122 
  123         bus = 0;
  124  retry:
  125         for (slot = 0; slot <= PCI_SLOTMAX; slot++) {
  126                 func = 0;
  127                 hdrtype = legacy_pcib_read_config(0, bus, slot, func,
  128                                                  PCIR_HDRTYPE, 1);
  129                 /*
  130                  * When enumerating bus devices, the standard says that
  131                  * one should check the header type and ignore the slots whose
  132                  * header types that the software doesn't know about.  We use
  133                  * this to filter out devices.
  134                  */
  135                 if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE)
  136                         continue;
  137                 if ((hdrtype & PCIM_MFDEV) &&
  138                     (!found_orion || hdrtype != 0xff))
  139                         pcifunchigh = PCI_FUNCMAX;
  140                 else
  141                         pcifunchigh = 0;
  142                 for (func = 0; func <= pcifunchigh; func++) {
  143                         /*
  144                          * Read the IDs and class from the device.
  145                          */
  146                         u_int32_t id;
  147                         u_int8_t class, subclass, busnum;
  148                         const char *s;
  149                         device_t *devs;
  150                         int ndevs, i;
  151 
  152                         id = legacy_pcib_read_config(0, bus, slot, func,
  153                                                     PCIR_DEVVENDOR, 4);
  154                         if (id == -1)
  155                                 continue;
  156                         class = legacy_pcib_read_config(0, bus, slot, func,
  157                                                        PCIR_CLASS, 1);
  158                         subclass = legacy_pcib_read_config(0, bus, slot, func,
  159                                                           PCIR_SUBCLASS, 1);
  160 
  161                         s = legacy_pcib_is_host_bridge(bus, slot, func,
  162                                                       id, class, subclass,
  163                                                       &busnum);
  164                         if (s == NULL)
  165                                 continue;
  166 
  167                         /*
  168                          * Check to see if the physical bus has already
  169                          * been seen.  Eg: hybrid 32 and 64 bit host
  170                          * bridges to the same logical bus.
  171                          */
  172                         if (device_get_children(parent, &devs, &ndevs) == 0) {
  173                                 for (i = 0; s != NULL && i < ndevs; i++) {
  174                                         if (strcmp(device_get_name(devs[i]),
  175                                             "pcib") != 0)
  176                                                 continue;
  177                                         if (legacy_get_pcibus(devs[i]) == busnum)
  178                                                 s = NULL;
  179                                 }
  180                                 free(devs, M_TEMP);
  181                         }
  182 
  183                         if (s == NULL)
  184                                 continue;
  185                         /*
  186                          * Add at priority 100 to make sure we
  187                          * go after any motherboard resources
  188                          */
  189                         child = BUS_ADD_CHILD(parent, 100,
  190                                               "pcib", busnum);
  191                         device_set_desc(child, s);
  192                         legacy_set_pcibus(child, busnum);
  193 
  194                         found = 1;
  195                         if (id == 0x12258086)
  196                                 found824xx = 1;
  197                         if (id == 0x84c48086)
  198                                 found_orion = 1;
  199                 }
  200         }
  201         if (found824xx && bus == 0) {
  202                 bus++;
  203                 goto retry;
  204         }
  205 
  206         /*
  207          * Make sure we add at least one bridge since some old
  208          * hardware doesn't actually have a host-pci bridge device.
  209          * Note that pci_cfgregopen() thinks we have PCI devices..
  210          */
  211         if (!found) {
  212                 if (bootverbose)
  213                         printf(
  214         "legacy_pcib_identify: no bridge found, adding pcib0 anyway\n");
  215                 child = BUS_ADD_CHILD(parent, 100, "pcib", 0);
  216                 legacy_set_pcibus(child, 0);
  217         }
  218 }
  219 
  220 static int
  221 legacy_pcib_probe(device_t dev)
  222 {
  223 
  224         if (pci_cfgregopen() == 0)
  225                 return ENXIO;
  226         return -100;
  227 }
  228 
  229 static int
  230 legacy_pcib_attach(device_t dev)
  231 {
  232         int bus;
  233 
  234         bus = pcib_get_bus(dev);
  235         device_add_child(dev, "pci", bus);
  236         return bus_generic_attach(dev);
  237 }
  238 
  239 int
  240 legacy_pcib_read_ivar(device_t dev, device_t child, int which,
  241     uintptr_t *result)
  242 {
  243 
  244         switch (which) {
  245         case  PCIB_IVAR_BUS:
  246                 *result = legacy_get_pcibus(dev);
  247                 return 0;
  248         }
  249         return ENOENT;
  250 }
  251 
  252 int
  253 legacy_pcib_write_ivar(device_t dev, device_t child, int which,
  254     uintptr_t value)
  255 {
  256 
  257         switch (which) {
  258         case  PCIB_IVAR_BUS:
  259                 legacy_set_pcibus(dev, value);
  260                 return 0;
  261         }
  262         return ENOENT;
  263 }
  264 
  265 
  266 static device_method_t legacy_pcib_methods[] = {
  267         /* Device interface */
  268         DEVMETHOD(device_identify,      legacy_pcib_identify),
  269         DEVMETHOD(device_probe,         legacy_pcib_probe),
  270         DEVMETHOD(device_attach,        legacy_pcib_attach),
  271         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  272         DEVMETHOD(device_suspend,       bus_generic_suspend),
  273         DEVMETHOD(device_resume,        bus_generic_resume),
  274 
  275         /* Bus interface */
  276         DEVMETHOD(bus_print_child,      bus_generic_print_child),
  277         DEVMETHOD(bus_read_ivar,        legacy_pcib_read_ivar),
  278         DEVMETHOD(bus_write_ivar,       legacy_pcib_write_ivar),
  279         DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
  280         DEVMETHOD(bus_release_resource, bus_generic_release_resource),
  281         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
  282         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
  283         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
  284         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
  285 
  286         /* pcib interface */
  287         DEVMETHOD(pcib_maxslots,        legacy_pcib_maxslots),
  288         DEVMETHOD(pcib_read_config,     legacy_pcib_read_config),
  289         DEVMETHOD(pcib_write_config,    legacy_pcib_write_config),
  290         DEVMETHOD(pcib_route_interrupt, legacy_pcib_route_interrupt),
  291 
  292         { 0, 0 }
  293 };
  294 
  295 static driver_t legacy_pcib_driver = {
  296         "pcib",
  297         legacy_pcib_methods,
  298         1,
  299 };
  300 
  301 DRIVER_MODULE(pcib, legacy, legacy_pcib_driver, pcib_devclass, 0, 0);
  302 
  303 
  304 /*
  305  * Provide a device to "eat" the host->pci bridges that we dug up above
  306  * and stop them showing up twice on the probes.  This also stops them
  307  * showing up as 'none' in pciconf -l.
  308  */
  309 static int
  310 pci_hostb_probe(device_t dev)
  311 {
  312         u_int32_t id;
  313 
  314         id = pci_get_devid(dev);
  315 
  316         switch (id) {
  317 
  318         /* VIA VT82C596 Power Managment Function */
  319         case 0x30501106:
  320                 return ENXIO;
  321 
  322         default:
  323                 break;
  324         }
  325 
  326         if (pci_get_class(dev) == PCIC_BRIDGE &&
  327             pci_get_subclass(dev) == PCIS_BRIDGE_HOST) {
  328                 device_set_desc(dev, "Host to PCI bridge");
  329                 device_quiet(dev);
  330                 return -10000;
  331         }
  332         return ENXIO;
  333 }
  334 
  335 static int
  336 pci_hostb_attach(device_t dev)
  337 {
  338 
  339         return 0;
  340 }
  341 
  342 static device_method_t pci_hostb_methods[] = {
  343         /* Device interface */
  344         DEVMETHOD(device_probe,         pci_hostb_probe),
  345         DEVMETHOD(device_attach,        pci_hostb_attach),
  346         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  347         DEVMETHOD(device_suspend,       bus_generic_suspend),
  348         DEVMETHOD(device_resume,        bus_generic_resume),
  349 
  350         { 0, 0 }
  351 };
  352 static driver_t pci_hostb_driver = {
  353         "hostb",
  354         pci_hostb_methods,
  355         1,
  356 };
  357 static devclass_t pci_hostb_devclass;
  358 
  359 DRIVER_MODULE(hostb, pci, pci_hostb_driver, pci_hostb_devclass, 0, 0);
  360 
  361 
  362 /*
  363  * Install placeholder to claim the resources owned by the
  364  * PCI bus interface.  This could be used to extract the
  365  * config space registers in the extreme case where the PnP
  366  * ID is available and the PCI BIOS isn't, but for now we just
  367  * eat the PnP ID and do nothing else.
  368  *
  369  * XXX we should silence this probe, as it will generally confuse
  370  * people.
  371  */
  372 static struct isa_pnp_id pcibus_pnp_ids[] = {
  373         { 0x030ad041 /* PNP0A03 */, "PCI Bus" },
  374         { 0 }
  375 };
  376 
  377 static int
  378 pcibus_pnp_probe(device_t dev)
  379 {
  380         int result;
  381 
  382         if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, pcibus_pnp_ids)) <= 0)
  383                 device_quiet(dev);
  384         return(result);
  385 }
  386 
  387 static int
  388 pcibus_pnp_attach(device_t dev)
  389 {
  390         return(0);
  391 }
  392 
  393 static device_method_t pcibus_pnp_methods[] = {
  394         /* Device interface */
  395         DEVMETHOD(device_probe,         pcibus_pnp_probe),
  396         DEVMETHOD(device_attach,        pcibus_pnp_attach),
  397         DEVMETHOD(device_detach,        bus_generic_detach),
  398         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  399         DEVMETHOD(device_suspend,       bus_generic_suspend),
  400         DEVMETHOD(device_resume,        bus_generic_resume),
  401         { 0, 0 }
  402 };
  403 
  404 static driver_t pcibus_pnp_driver = {
  405         "pcibus_pnp",
  406         pcibus_pnp_methods,
  407         1,              /* no softc */
  408 };
  409 
  410 static devclass_t pcibus_pnp_devclass;
  411 
  412 DRIVER_MODULE(pcibus_pnp, isa, pcibus_pnp_driver, pcibus_pnp_devclass, 0, 0);

Cache object: 806448698ef75e520c0f601e1720b201


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.