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/i386/isa/pcibus.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  * $FreeBSD$
   27  *
   28  */
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/kernel.h>
   34 
   35 #include <pci/pcivar.h>
   36 #include <pci/pcireg.h>
   37 #include <i386/isa/pcibus.h>
   38 #include <machine/pci_cfgreg.h>
   39 #include <machine/md_var.h>
   40 
   41 #include "opt_cpu.h"
   42 
   43 #include "pci_if.h"
   44 
   45 static devclass_t       pcib_devclass;
   46 
   47 static const char *
   48 nexus_pcib_is_host_bridge(pcicfgregs *cfg,
   49                           u_int32_t id, u_int8_t class, u_int8_t subclass,
   50                           u_int8_t *busnum)
   51 {
   52         const char *s = NULL;
   53         static u_int8_t pxb[4]; /* hack for 450nx */
   54 
   55         *busnum = 0;
   56 
   57         switch (id) {
   58         case 0x12258086:
   59                 s = "Intel 824?? host to PCI bridge";
   60                 /* XXX This is a guess */
   61                 /* *busnum = pci_cfgread(cfg, 0x41, 1); */
   62                 *busnum = cfg->bus;
   63                 break;
   64         case 0x71208086:
   65                 s = "Intel 82810 (i810 GMCH) Host To Hub bridge";
   66                 break;
   67         case 0x71228086:
   68                 s = "Intel 82810-DC100 (i810-DC100 GMCH) Host To Hub bridge";
   69                 break;
   70         case 0x71248086:
   71                 s = "Intel 82810E (i810E GMCH) Host To Hub bridge";
   72                 break;
   73         case 0x71808086:
   74                 s = "Intel 82443LX (440 LX) host to PCI bridge";
   75                 break;
   76         case 0x71908086:
   77                 s = "Intel 82443BX (440 BX) host to PCI bridge";
   78                 break;
   79         case 0x71928086:
   80                 s = "Intel 82443BX host to PCI bridge (AGP disabled)";
   81                 break;
   82         case 0x71948086:
   83                 s = "Intel 82443MX host to PCI bridge";
   84                 break;
   85         case 0x71a08086:
   86                 s = "Intel 82443GX host to PCI bridge";
   87                 break;
   88         case 0x71a18086:
   89                 s = "Intel 82443GX host to AGP bridge";
   90                 break;
   91         case 0x71a28086:
   92                 s = "Intel 82443GX host to PCI bridge (AGP disabled)";
   93                 break;
   94         case 0x84c48086:
   95                 s = "Intel 82454KX/GX (Orion) host to PCI bridge";
   96                 *busnum = pci_cfgread(cfg, 0x4a, 1);
   97                 break;
   98         case 0x84ca8086:
   99                 /*
  100                  * For the 450nx chipset, there is a whole bundle of
  101                  * things pretending to be host bridges. The MIOC will 
  102                  * be seen first and isn't really a pci bridge (the
  103                  * actual busses are attached to the PXB's). We need to 
  104                  * read the registers of the MIOC to figure out the
  105                  * bus numbers for the PXB channels.
  106                  *
  107                  * Since the MIOC doesn't have a pci bus attached, we
  108                  * pretend it wasn't there.
  109                  */
  110                 pxb[0] = pci_cfgread(cfg, 0xd0, 1); /* BUSNO[0] */
  111                 pxb[1] = pci_cfgread(cfg, 0xd1, 1) + 1; /* SUBA[0]+1 */
  112                 pxb[2] = pci_cfgread(cfg, 0xd3, 1); /* BUSNO[1] */
  113                 pxb[3] = pci_cfgread(cfg, 0xd4, 1) + 1; /* SUBA[1]+1 */
  114                 return NULL;
  115         case 0x84cb8086:
  116                 switch (cfg->slot) {
  117                 case 0x12:
  118                         s = "Intel 82454NX PXB#0, Bus#A";
  119                         *busnum = pxb[0];
  120                         break;
  121                 case 0x13:
  122                         s = "Intel 82454NX PXB#0, Bus#B";
  123                         *busnum = pxb[1];
  124                         break;
  125                 case 0x14:
  126                         s = "Intel 82454NX PXB#1, Bus#A";
  127                         *busnum = pxb[2];
  128                         break;
  129                 case 0x15:
  130                         s = "Intel 82454NX PXB#1, Bus#B";
  131                         *busnum = pxb[3];
  132                         break;
  133                 }
  134                 break;
  135         case 0x1A308086:
  136                 s = "Intel 82845 Host to PCI bridge";
  137                 break;
  138 
  139                 /* AMD -- vendor 0x1022 */
  140         case 0x30001022:
  141                 s = "AMD Elan SC520 host to PCI bridge";
  142 #ifdef CPU_ELAN
  143                 init_AMD_Elan_sc520();
  144 #else
  145                 printf("*** WARNING: kernel option CPU_ELAN missing");
  146                 printf("-- timekeeping may be wrong\n");
  147 #endif
  148                 break;
  149         case 0x70061022:
  150                 s = "AMD-751 host to PCI bridge";
  151                 break;
  152         case 0x700e1022:
  153                 s = "AMD-761 host to PCI bridge";
  154                 break;
  155 
  156                 /* SiS -- vendor 0x1039 */
  157         case 0x04961039:
  158                 s = "SiS 85c496";
  159                 break;
  160         case 0x04061039:
  161                 s = "SiS 85c501";
  162                 break;
  163         case 0x06011039:
  164                 s = "SiS 85c601";
  165                 break;
  166         case 0x55911039:
  167                 s = "SiS 5591 host to PCI bridge";
  168                 break;
  169         case 0x00011039:
  170                 s = "SiS 5591 host to AGP bridge";
  171                 break;
  172 
  173                 /* VLSI -- vendor 0x1004 */
  174         case 0x00051004:
  175                 s = "VLSI 82C592 Host to PCI bridge";
  176                 break;
  177 
  178                 /* XXX Here is MVP3, I got the datasheet but NO M/B to test it  */
  179                 /* totally. Please let me know if anything wrong.            -F */
  180                 /* XXX need info on the MVP3 -- any takers? */
  181         case 0x05981106:
  182                 s = "VIA 82C598MVP (Apollo MVP3) host bridge";
  183                 break;
  184 
  185                 /* AcerLabs -- vendor 0x10b9 */
  186                 /* Funny : The datasheet told me vendor id is "10b8",sub-vendor */
  187                 /* id is '10b9" but the register always shows "10b9". -Foxfair  */
  188         case 0x154110b9:
  189                 s = "AcerLabs M1541 (Aladdin-V) PCI host bridge";
  190                 break;
  191 
  192                 /* OPTi -- vendor 0x1045 */
  193         case 0xc8221045:
  194                 s = "OPTi 82C822 host to PCI Bridge";
  195                 break;
  196 
  197                 /* ServerWorks -- vendor 0x1166 */
  198         case 0x00051166:
  199                 s = "ServerWorks NB6536 2.0HE host to PCI bridge";
  200                 *busnum = pci_cfgread(cfg, 0x44, 1);
  201                 break;
  202         
  203         case 0x00061166:
  204                 /* FALLTHROUGH */
  205         case 0x00081166:
  206                 s = "ServerWorks host to PCI bridge";
  207                 *busnum = pci_cfgread(cfg, 0x44, 1);
  208                 break;
  209 
  210         case 0x00091166:
  211                 s = "ServerWorks NB6635 3.0LE host to PCI bridge";
  212                 *busnum = pci_cfgread(cfg, 0x44, 1);
  213                 break;
  214 
  215         case 0x00101166:
  216                 s = "ServerWorks CIOB30 host to PCI bridge";
  217                 *busnum = pci_cfgread(cfg, 0x44, 1);
  218                 break;
  219 
  220                 /* XXX unknown chipset, but working */
  221         case 0x00171166:
  222                 /* FALLTHROUGH */
  223         case 0x01011166:
  224                 s = "ServerWorks host to PCI bridge(unknown chipset)";
  225                 *busnum = pci_cfgread(cfg, 0x44, 1);
  226                 break;
  227 
  228                 /* Integrated Micro Solutions -- vendor 0x10e0 */
  229         case 0x884910e0:
  230                 s = "Integrated Micro Solutions VL Bridge";
  231                 break;
  232 
  233         default:
  234                 if (class == PCIC_BRIDGE && subclass == PCIS_BRIDGE_HOST)
  235                         s = "Host to PCI bridge";
  236                 break;
  237         }
  238 
  239         return s;
  240 }
  241 
  242 /*
  243  * Scan the first pci bus for host-pci bridges and add pcib instances
  244  * to the nexus for each bridge.
  245  */
  246 static void
  247 nexus_pcib_identify(driver_t *driver, device_t parent)
  248 {
  249         pcicfgregs probe;
  250         u_int8_t  hdrtype;
  251         int found = 0;
  252         int pcifunchigh;
  253         int found824xx = 0;
  254         int found_orion = 0;
  255 
  256         if (pci_cfgregopen() == 0)
  257                 return;
  258         probe.hose = 0;
  259         probe.bus = 0;
  260  retry:
  261         for (probe.slot = 0; probe.slot <= PCI_SLOTMAX; probe.slot++) {
  262                 probe.func = 0;
  263                 hdrtype = pci_cfgread(&probe, PCIR_HEADERTYPE, 1);
  264                 if ((hdrtype & ~PCIM_MFDEV) > 2)
  265                         continue;
  266                 if (hdrtype & PCIM_MFDEV && (!found_orion || hdrtype != 0xff) )
  267                         pcifunchigh = 7;
  268                 else
  269                         pcifunchigh = 0;
  270                 for (probe.func = 0;
  271                      probe.func <= pcifunchigh;
  272                      probe.func++) {
  273                         /*
  274                          * Read the IDs and class from the device.
  275                          */
  276                         u_int32_t id;
  277                         u_int8_t class, subclass, busnum;
  278                         device_t child;
  279                         const char *s;
  280 
  281                         id = pci_cfgread(&probe, PCIR_DEVVENDOR, 4);
  282                         if (id == -1)
  283                                 continue;
  284                         class = pci_cfgread(&probe, PCIR_CLASS, 1);
  285                         subclass = pci_cfgread(&probe, PCIR_SUBCLASS, 1);
  286 
  287                         s = nexus_pcib_is_host_bridge(&probe, id,
  288                                                       class, subclass,
  289                                                       &busnum);
  290                         if (s) {
  291                                 /*
  292                                  * Add at priority 100 to make sure we
  293                                  * go after any motherboard resources
  294                                  */
  295                                 child = BUS_ADD_CHILD(parent, 100,
  296                                                       "pcib", busnum);
  297                                 device_set_desc(child, s);
  298                                 found = 1;
  299                                 if (id == 0x12258086)
  300                                         found824xx = 1;
  301                                 if (id == 0x84c48086)
  302                                         found_orion = 1;
  303                         }
  304                 }
  305         }
  306         if (found824xx && probe.bus == 0) {
  307                 probe.bus++;
  308                 goto retry;
  309         }
  310 
  311         /*
  312          * Make sure we add at least one bridge since some old
  313          * hardware doesn't actually have a host-pci bridge device.
  314          * Note that pci_cfgregopen() thinks we have PCI devices..
  315          */
  316         if (!found) {
  317                 if (bootverbose)
  318                         printf(
  319         "nexus_pcib_identify: no bridge found, adding pcib0 anyway\n");
  320                 BUS_ADD_CHILD(parent, 100, "pcib", 0);
  321         }
  322 }
  323 
  324 static int
  325 nexus_pcib_probe(device_t dev)
  326 {
  327         if (pci_cfgregopen() != 0) {
  328                 device_add_child(dev, "pci", device_get_unit(dev));
  329                 return 0;
  330         }
  331         return ENXIO;
  332 }
  333 
  334 /* route interrupt */
  335 
  336 static int
  337 nexus_pcib_route_interrupt(device_t pcib, device_t dev, int pin)
  338 {
  339         return(pci_cfgintr(pci_get_bus(dev), pci_get_slot(dev), pin));
  340 }
  341 
  342 static device_method_t nexus_pcib_methods[] = {
  343         /* Device interface */
  344         DEVMETHOD(device_identify,      nexus_pcib_identify),
  345         DEVMETHOD(device_probe,         nexus_pcib_probe),
  346         DEVMETHOD(device_attach,        bus_generic_attach),
  347         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  348         DEVMETHOD(device_suspend,       bus_generic_suspend),
  349         DEVMETHOD(device_resume,        bus_generic_resume),
  350 
  351         /* Bus interface */
  352         DEVMETHOD(bus_print_child,      bus_generic_print_child),
  353         DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
  354         DEVMETHOD(bus_release_resource, bus_generic_release_resource),
  355         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
  356         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
  357         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
  358         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
  359 
  360         /* pci interface */
  361         DEVMETHOD(pci_route_interrupt,  nexus_pcib_route_interrupt),
  362         { 0, 0 }
  363 };
  364 
  365 static driver_t nexus_pcib_driver = {
  366         "pcib",
  367         nexus_pcib_methods,
  368         1,
  369 };
  370 
  371 DRIVER_MODULE(pcib, nexus, nexus_pcib_driver, pcib_devclass, 0, 0);

Cache object: 7b4071e9d5fd392fc7769f87baf0eb80


[ 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.