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/pci/pci_cfgreg.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  * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
    4  * Copyright (c) 2000, BSDi
    5  * Copyright (c) 2004, Scott Long <scottl@freebsd.org>
    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 unmodified, this list of conditions, and the following
   13  *    disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 #include <sys/lock.h>
   37 #include <sys/mutex.h>
   38 #include <dev/pci/pcivar.h>
   39 #include <dev/pci/pcireg.h>
   40 #include <machine/pci_cfgreg.h>
   41 #include <machine/pc/bios.h>
   42 
   43 #define PRVERB(a) do {                                                  \
   44         if (bootverbose)                                                \
   45                 printf a ;                                              \
   46 } while(0)
   47 
   48 static int cfgmech;
   49 static int devmax;
   50 
   51 static int      pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
   52 static void     pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
   53 static int      pcireg_cfgopen(void);
   54 
   55 static struct mtx pcicfg_mtx;
   56 
   57 /*
   58  * Some BIOS writers seem to want to ignore the spec and put
   59  * 0 in the intline rather than 255 to indicate none.  Some use
   60  * numbers in the range 128-254 to indicate something strange and
   61  * apparently undocumented anywhere.  Assume these are completely bogus
   62  * and map them to 255, which means "none".
   63  */
   64 static __inline int 
   65 pci_i386_map_intline(int line)
   66 {
   67         if (line == 0 || line >= 128)
   68                 return (PCI_INVALID_IRQ);
   69         return (line);
   70 }
   71 
   72 static u_int16_t
   73 pcibios_get_version(void)
   74 {
   75         struct bios_regs args;
   76 
   77         if (PCIbios.ventry == 0) {
   78                 PRVERB(("pcibios: No call entry point\n"));
   79                 return (0);
   80         }
   81         args.eax = PCIBIOS_BIOS_PRESENT;
   82         if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
   83                 PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
   84                 return (0);
   85         }
   86         if (args.edx != 0x20494350) {
   87                 PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
   88                 return (0);
   89         }
   90         return (args.ebx & 0xffff);
   91 }
   92 
   93 /* 
   94  * Initialise access to PCI configuration space 
   95  */
   96 int
   97 pci_cfgregopen(void)
   98 {
   99         static int              opened = 0;
  100         u_int16_t               v;
  101 
  102         if (opened)
  103                 return(1);
  104 
  105         if (pcireg_cfgopen() == 0)
  106                 return(0);
  107 
  108         v = pcibios_get_version();
  109         if (v > 0)
  110                 PRVERB(("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8,
  111                     v & 0xff));
  112         mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
  113         opened = 1;
  114 
  115         /* $PIR requires PCI BIOS 2.10 or greater. */
  116         if (v >= 0x0210)
  117                 pci_pir_open();
  118         return(1);
  119 }
  120 
  121 /* 
  122  * Read configuration space register
  123  */
  124 u_int32_t
  125 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
  126 {
  127         uint32_t line;
  128 
  129         /*
  130          * Some BIOS writers seem to want to ignore the spec and put
  131          * 0 in the intline rather than 255 to indicate none.  The rest of
  132          * the code uses 255 as an invalid IRQ.
  133          */
  134         if (reg == PCIR_INTLINE && bytes == 1) {
  135                 line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
  136                 return (pci_i386_map_intline(line));
  137         }
  138         return (pcireg_cfgread(bus, slot, func, reg, bytes));
  139 }
  140 
  141 /* 
  142  * Write configuration space register 
  143  */
  144 void
  145 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
  146 {
  147 
  148         pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
  149 }
  150 
  151 /* 
  152  * Configuration space access using direct register operations
  153  */
  154 
  155 /* enable configuration space accesses and return data port address */
  156 static int
  157 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
  158 {
  159         int dataport = 0;
  160 
  161         if (bus <= PCI_BUSMAX
  162             && slot < devmax
  163             && func <= PCI_FUNCMAX
  164             && reg <= PCI_REGMAX
  165             && bytes != 3
  166             && (unsigned) bytes <= 4
  167             && (reg & (bytes - 1)) == 0) {
  168                 switch (cfgmech) {
  169                 case 1:
  170                         outl(CONF1_ADDR_PORT, (1 << 31)
  171                             | (bus << 16) | (slot << 11) 
  172                             | (func << 8) | (reg & ~0x03));
  173                         dataport = CONF1_DATA_PORT + (reg & 0x03);
  174                         break;
  175                 case 2:
  176                         outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
  177                         outb(CONF2_FORWARD_PORT, bus);
  178                         dataport = 0xc000 | (slot << 8) | reg;
  179                         break;
  180                 }
  181         }
  182         return (dataport);
  183 }
  184 
  185 /* disable configuration space accesses */
  186 static void
  187 pci_cfgdisable(void)
  188 {
  189         switch (cfgmech) {
  190         case 1:
  191                 outl(CONF1_ADDR_PORT, 0);
  192                 break;
  193         case 2:
  194                 outb(CONF2_ENABLE_PORT, 0);
  195                 outb(CONF2_FORWARD_PORT, 0);
  196                 break;
  197         }
  198 }
  199 
  200 static int
  201 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
  202 {
  203         int data = -1;
  204         int port;
  205 
  206         mtx_lock_spin(&pcicfg_mtx);
  207         port = pci_cfgenable(bus, slot, func, reg, bytes);
  208         if (port != 0) {
  209                 switch (bytes) {
  210                 case 1:
  211                         data = inb(port);
  212                         break;
  213                 case 2:
  214                         data = inw(port);
  215                         break;
  216                 case 4:
  217                         data = inl(port);
  218                         break;
  219                 }
  220                 pci_cfgdisable();
  221         }
  222         mtx_unlock_spin(&pcicfg_mtx);
  223         return (data);
  224 }
  225 
  226 static void
  227 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
  228 {
  229         int port;
  230 
  231         mtx_lock_spin(&pcicfg_mtx);
  232         port = pci_cfgenable(bus, slot, func, reg, bytes);
  233         if (port != 0) {
  234                 switch (bytes) {
  235                 case 1:
  236                         outb(port, data);
  237                         break;
  238                 case 2:
  239                         outw(port, data);
  240                         break;
  241                 case 4:
  242                         outl(port, data);
  243                         break;
  244                 }
  245                 pci_cfgdisable();
  246         }
  247         mtx_unlock_spin(&pcicfg_mtx);
  248 }
  249 
  250 /* check whether the configuration mechanism has been correctly identified */
  251 static int
  252 pci_cfgcheck(int maxdev)
  253 {
  254         uint32_t id, class;
  255         uint8_t header;
  256         uint8_t device;
  257         int port;
  258 
  259         if (bootverbose) 
  260                 printf("pci_cfgcheck:\tdevice ");
  261 
  262         for (device = 0; device < maxdev; device++) {
  263                 if (bootverbose) 
  264                         printf("%d ", device);
  265 
  266                 port = pci_cfgenable(0, device, 0, 0, 4);
  267                 id = inl(port);
  268                 if (id == 0 || id == 0xffffffff)
  269                         continue;
  270 
  271                 port = pci_cfgenable(0, device, 0, 8, 4);
  272                 class = inl(port) >> 8;
  273                 if (bootverbose)
  274                         printf("[class=%06x] ", class);
  275                 if (class == 0 || (class & 0xf870ff) != 0)
  276                         continue;
  277 
  278                 port = pci_cfgenable(0, device, 0, 14, 1);
  279                 header = inb(port);
  280                 if (bootverbose)
  281                         printf("[hdr=%02x] ", header);
  282                 if ((header & 0x7e) != 0)
  283                         continue;
  284 
  285                 if (bootverbose)
  286                         printf("is there (id=%08x)\n", id);
  287 
  288                 pci_cfgdisable();
  289                 return (1);
  290         }
  291         if (bootverbose) 
  292                 printf("-- nothing found\n");
  293 
  294         pci_cfgdisable();
  295         return (0);
  296 }
  297 
  298 static int
  299 pcireg_cfgopen(void)
  300 {
  301         uint32_t mode1res, oldval1;
  302         uint8_t mode2res, oldval2;
  303 
  304         oldval1 = inl(CONF1_ADDR_PORT);
  305 
  306         if (bootverbose) {
  307                 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
  308                     oldval1);
  309         }
  310 
  311         if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
  312 
  313                 cfgmech = 1;
  314                 devmax = 32;
  315 
  316                 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
  317                 DELAY(1);
  318                 mode1res = inl(CONF1_ADDR_PORT);
  319                 outl(CONF1_ADDR_PORT, oldval1);
  320 
  321                 if (bootverbose)
  322                         printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", 
  323                             mode1res, CONF1_ENABLE_CHK);
  324 
  325                 if (mode1res) {
  326                         if (pci_cfgcheck(32)) 
  327                                 return (cfgmech);
  328                 }
  329 
  330                 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
  331                 mode1res = inl(CONF1_ADDR_PORT);
  332                 outl(CONF1_ADDR_PORT, oldval1);
  333 
  334                 if (bootverbose)
  335                         printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", 
  336                             mode1res, CONF1_ENABLE_CHK1);
  337 
  338                 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
  339                         if (pci_cfgcheck(32)) 
  340                                 return (cfgmech);
  341                 }
  342         }
  343 
  344         oldval2 = inb(CONF2_ENABLE_PORT);
  345 
  346         if (bootverbose) {
  347                 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
  348                     oldval2);
  349         }
  350 
  351         if ((oldval2 & 0xf0) == 0) {
  352 
  353                 cfgmech = 2;
  354                 devmax = 16;
  355 
  356                 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
  357                 mode2res = inb(CONF2_ENABLE_PORT);
  358                 outb(CONF2_ENABLE_PORT, oldval2);
  359 
  360                 if (bootverbose)
  361                         printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
  362                             mode2res, CONF2_ENABLE_CHK);
  363 
  364                 if (mode2res == CONF2_ENABLE_RES) {
  365                         if (bootverbose)
  366                                 printf("pci_open(2a):\tnow trying mechanism 2\n");
  367 
  368                         if (pci_cfgcheck(16)) 
  369                                 return (cfgmech);
  370                 }
  371         }
  372 
  373         cfgmech = 0;
  374         devmax = 0;
  375         return (cfgmech);
  376 }
  377 

Cache object: 7275a0cb793db1846da3872bd95adfcf


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