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

Cache object: 01e10652cac2fcfc2e2b6102b362fb38


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