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_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$");
   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 
   41 static int cfgmech;
   42 static int devmax;
   43 
   44 static int      pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
   45 static void     pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
   46 static int      pcireg_cfgopen(void);
   47 
   48 static struct mtx pcicfg_mtx;
   49 
   50 /* 
   51  * Initialise access to PCI configuration space 
   52  */
   53 int
   54 pci_cfgregopen(void)
   55 {
   56         static int              opened = 0;
   57 
   58         if (opened)
   59                 return (1);
   60         if (pcireg_cfgopen() == 0)
   61                 return (0);
   62         mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
   63         opened = 1;
   64         return (1);
   65 }
   66 
   67 /* 
   68  * Read configuration space register
   69  */
   70 u_int32_t
   71 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
   72 {
   73         uint32_t line;
   74 
   75         /*
   76          * Some BIOS writers seem to want to ignore the spec and put
   77          * 0 in the intline rather than 255 to indicate none.  Some use
   78          * numbers in the range 128-254 to indicate something strange and
   79          * apparently undocumented anywhere.  Assume these are completely bogus
   80          * and map them to 255, which the rest of the PCI code recognizes as
   81          * as an invalid IRQ.
   82          */
   83         if (reg == PCIR_INTLINE && bytes == 1) {
   84                 line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
   85                 if (line == 0 || line >= 128)
   86                         line = PCI_INVALID_IRQ;
   87                 return (line);
   88         }
   89         return (pcireg_cfgread(bus, slot, func, reg, bytes));
   90 }
   91 
   92 /* 
   93  * Write configuration space register 
   94  */
   95 void
   96 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
   97 {
   98 
   99         pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
  100 }
  101 
  102 /* 
  103  * Configuration space access using direct register operations
  104  */
  105 
  106 /* enable configuration space accesses and return data port address */
  107 static int
  108 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
  109 {
  110         int dataport = 0;
  111 
  112         if (bus <= PCI_BUSMAX
  113             && slot < devmax
  114             && func <= PCI_FUNCMAX
  115             && reg <= PCI_REGMAX
  116             && bytes != 3
  117             && (unsigned) bytes <= 4
  118             && (reg & (bytes - 1)) == 0) {
  119                 switch (cfgmech) {
  120                 case 1:
  121                         outl(CONF1_ADDR_PORT, (1 << 31)
  122                             | (bus << 16) | (slot << 11) 
  123                             | (func << 8) | (reg & ~0x03));
  124                         dataport = CONF1_DATA_PORT + (reg & 0x03);
  125                         break;
  126                 case 2:
  127                         outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
  128                         outb(CONF2_FORWARD_PORT, bus);
  129                         dataport = 0xc000 | (slot << 8) | reg;
  130                         break;
  131                 }
  132         }
  133         return (dataport);
  134 }
  135 
  136 /* disable configuration space accesses */
  137 static void
  138 pci_cfgdisable(void)
  139 {
  140         switch (cfgmech) {
  141         case 1:
  142                 outl(CONF1_ADDR_PORT, 0);
  143                 break;
  144         case 2:
  145                 outb(CONF2_ENABLE_PORT, 0);
  146                 outb(CONF2_FORWARD_PORT, 0);
  147                 break;
  148         }
  149 }
  150 
  151 static int
  152 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
  153 {
  154         int data = -1;
  155         int port;
  156 
  157         mtx_lock_spin(&pcicfg_mtx);
  158         port = pci_cfgenable(bus, slot, func, reg, bytes);
  159         if (port != 0) {
  160                 switch (bytes) {
  161                 case 1:
  162                         data = inb(port);
  163                         break;
  164                 case 2:
  165                         data = inw(port);
  166                         break;
  167                 case 4:
  168                         data = inl(port);
  169                         break;
  170                 }
  171                 pci_cfgdisable();
  172         }
  173         mtx_unlock_spin(&pcicfg_mtx);
  174         return (data);
  175 }
  176 
  177 static void
  178 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
  179 {
  180         int port;
  181 
  182         mtx_lock_spin(&pcicfg_mtx);
  183         port = pci_cfgenable(bus, slot, func, reg, bytes);
  184         if (port != 0) {
  185                 switch (bytes) {
  186                 case 1:
  187                         outb(port, data);
  188                         break;
  189                 case 2:
  190                         outw(port, data);
  191                         break;
  192                 case 4:
  193                         outl(port, data);
  194                         break;
  195                 }
  196                 pci_cfgdisable();
  197         }
  198         mtx_unlock_spin(&pcicfg_mtx);
  199 }
  200 
  201 /* check whether the configuration mechanism has been correctly identified */
  202 static int
  203 pci_cfgcheck(int maxdev)
  204 {
  205         uint32_t id, class;
  206         uint8_t header;
  207         uint8_t device;
  208         int port;
  209 
  210         if (bootverbose) 
  211                 printf("pci_cfgcheck:\tdevice ");
  212 
  213         for (device = 0; device < maxdev; device++) {
  214                 if (bootverbose) 
  215                         printf("%d ", device);
  216 
  217                 port = pci_cfgenable(0, device, 0, 0, 4);
  218                 id = inl(port);
  219                 if (id == 0 || id == 0xffffffff)
  220                         continue;
  221 
  222                 port = pci_cfgenable(0, device, 0, 8, 4);
  223                 class = inl(port) >> 8;
  224                 if (bootverbose)
  225                         printf("[class=%06x] ", class);
  226                 if (class == 0 || (class & 0xf870ff) != 0)
  227                         continue;
  228 
  229                 port = pci_cfgenable(0, device, 0, 14, 1);
  230                 header = inb(port);
  231                 if (bootverbose)
  232                         printf("[hdr=%02x] ", header);
  233                 if ((header & 0x7e) != 0)
  234                         continue;
  235 
  236                 if (bootverbose)
  237                         printf("is there (id=%08x)\n", id);
  238 
  239                 pci_cfgdisable();
  240                 return (1);
  241         }
  242         if (bootverbose) 
  243                 printf("-- nothing found\n");
  244 
  245         pci_cfgdisable();
  246         return (0);
  247 }
  248 
  249 static int
  250 pcireg_cfgopen(void)
  251 {
  252         uint32_t mode1res, oldval1;
  253         uint8_t mode2res, oldval2;
  254 
  255         oldval1 = inl(CONF1_ADDR_PORT);
  256 
  257         if (bootverbose) {
  258                 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
  259                     oldval1);
  260         }
  261 
  262         if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
  263 
  264                 cfgmech = 1;
  265                 devmax = 32;
  266 
  267                 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
  268                 DELAY(1);
  269                 mode1res = inl(CONF1_ADDR_PORT);
  270                 outl(CONF1_ADDR_PORT, oldval1);
  271 
  272                 if (bootverbose)
  273                         printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", 
  274                             mode1res, CONF1_ENABLE_CHK);
  275 
  276                 if (mode1res) {
  277                         if (pci_cfgcheck(32)) 
  278                                 return (cfgmech);
  279                 }
  280 
  281                 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
  282                 mode1res = inl(CONF1_ADDR_PORT);
  283                 outl(CONF1_ADDR_PORT, oldval1);
  284 
  285                 if (bootverbose)
  286                         printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", 
  287                             mode1res, CONF1_ENABLE_CHK1);
  288 
  289                 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
  290                         if (pci_cfgcheck(32)) 
  291                                 return (cfgmech);
  292                 }
  293         }
  294 
  295         oldval2 = inb(CONF2_ENABLE_PORT);
  296 
  297         if (bootverbose) {
  298                 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
  299                     oldval2);
  300         }
  301 
  302         if ((oldval2 & 0xf0) == 0) {
  303 
  304                 cfgmech = 2;
  305                 devmax = 16;
  306 
  307                 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
  308                 mode2res = inb(CONF2_ENABLE_PORT);
  309                 outb(CONF2_ENABLE_PORT, oldval2);
  310 
  311                 if (bootverbose)
  312                         printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
  313                             mode2res, CONF2_ENABLE_CHK);
  314 
  315                 if (mode2res == CONF2_ENABLE_RES) {
  316                         if (bootverbose)
  317                                 printf("pci_open(2a):\tnow trying mechanism 2\n");
  318 
  319                         if (pci_cfgcheck(16)) 
  320                                 return (cfgmech);
  321                 }
  322         }
  323 
  324         cfgmech = 0;
  325         devmax = 0;
  326         return (cfgmech);
  327 }

Cache object: aeea1eb66341458822d7e76a4551c579


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