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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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: releng/6.2/sys/i386/pci/pci_cfgreg.c 161534 2006-08-22 16:52:42Z rink $");
   32 
   33 #include "opt_xbox.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/bus.h>
   38 #include <sys/lock.h>
   39 #include <sys/mutex.h>
   40 #include <sys/malloc.h>
   41 #include <sys/queue.h>
   42 #include <dev/pci/pcivar.h>
   43 #include <dev/pci/pcireg.h>
   44 #include <machine/pci_cfgreg.h>
   45 #include <machine/pc/bios.h>
   46 
   47 #include <vm/vm.h>
   48 #include <vm/vm_param.h>
   49 #include <vm/vm_kern.h>
   50 #include <vm/vm_extern.h>
   51 #include <vm/pmap.h>
   52 #include <machine/pmap.h>
   53 
   54 #ifdef XBOX
   55 #include <machine/xbox.h>
   56 #endif
   57 
   58 #define PRVERB(a) do {                                                  \
   59         if (bootverbose)                                                \
   60                 printf a ;                                              \
   61 } while(0)
   62 
   63 #define PCIE_CACHE 8
   64 struct pcie_cfg_elem {
   65         TAILQ_ENTRY(pcie_cfg_elem)      elem;
   66         vm_offset_t     vapage;
   67         vm_paddr_t      papage;
   68 };
   69 
   70 enum {
   71         CFGMECH_NONE = 0,
   72         CFGMECH_1,
   73         CFGMECH_2,
   74         CFGMECH_PCIE,
   75 };
   76 
   77 static TAILQ_HEAD(pcie_cfg_list, pcie_cfg_elem) pcie_list[MAXCPU];
   78 static uint32_t pciebar;
   79 static int cfgmech;
   80 static int devmax;
   81 static struct mtx pcicfg_mtx;
   82 
   83 static int      pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
   84 static void     pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
   85 static int      pcireg_cfgopen(void);
   86 
   87 static int      pciereg_cfgopen(void);
   88 static int      pciereg_cfgread(int bus, int slot, int func, int reg,
   89                                 int bytes);
   90 static void     pciereg_cfgwrite(int bus, int slot, int func, int reg,
   91                                  int data, int bytes);
   92 
   93 /*
   94  * Some BIOS writers seem to want to ignore the spec and put
   95  * 0 in the intline rather than 255 to indicate none.  Some use
   96  * numbers in the range 128-254 to indicate something strange and
   97  * apparently undocumented anywhere.  Assume these are completely bogus
   98  * and map them to 255, which means "none".
   99  */
  100 static __inline int 
  101 pci_i386_map_intline(int line)
  102 {
  103         if (line == 0 || line >= 128)
  104                 return (PCI_INVALID_IRQ);
  105         return (line);
  106 }
  107 
  108 static u_int16_t
  109 pcibios_get_version(void)
  110 {
  111         struct bios_regs args;
  112 
  113         if (PCIbios.ventry == 0) {
  114                 PRVERB(("pcibios: No call entry point\n"));
  115                 return (0);
  116         }
  117         args.eax = PCIBIOS_BIOS_PRESENT;
  118         if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
  119                 PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
  120                 return (0);
  121         }
  122         if (args.edx != 0x20494350) {
  123                 PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
  124                 return (0);
  125         }
  126         return (args.ebx & 0xffff);
  127 }
  128 
  129 /* 
  130  * Initialise access to PCI configuration space 
  131  */
  132 int
  133 pci_cfgregopen(void)
  134 {
  135         static int              opened = 0;
  136         u_int16_t               vid, did;
  137         u_int16_t               v;
  138 
  139         if (opened)
  140                 return(1);
  141 
  142         if (pcireg_cfgopen() == 0)
  143                 return(0);
  144 
  145         v = pcibios_get_version();
  146         if (v > 0)
  147                 PRVERB(("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8,
  148                     v & 0xff));
  149         mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
  150         opened = 1;
  151 
  152         /* $PIR requires PCI BIOS 2.10 or greater. */
  153         if (v >= 0x0210)
  154                 pci_pir_open();
  155 
  156         /*
  157          * Grope around in the PCI config space to see if this is a
  158          * chipset that is capable of doing memory-mapped config cycles.
  159          * This also implies that it can do PCIe extended config cycles.
  160          */
  161 
  162         /* Check for the Intel 7520 and 925 chipsets */
  163         vid = pci_cfgregread(0, 0, 0, 0x0, 2);
  164         did = pci_cfgregread(0, 0, 0, 0x2, 2);
  165         if ((vid == 0x8086) && (did == 0x3590)) {
  166                 pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16;
  167                 pciereg_cfgopen();
  168         } else if ((vid == 0x8086) && (did == 0x2580)) {
  169                 pciebar = pci_cfgregread(0, 0, 0, 0x48, 4);
  170                 pciereg_cfgopen();
  171         }
  172 
  173         return(1);
  174 }
  175 
  176 /* 
  177  * Read configuration space register
  178  */
  179 u_int32_t
  180 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
  181 {
  182         uint32_t line;
  183 
  184         /*
  185          * Some BIOS writers seem to want to ignore the spec and put
  186          * 0 in the intline rather than 255 to indicate none.  The rest of
  187          * the code uses 255 as an invalid IRQ.
  188          */
  189         if (reg == PCIR_INTLINE && bytes == 1) {
  190                 line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
  191                 return (pci_i386_map_intline(line));
  192         }
  193         return (pcireg_cfgread(bus, slot, func, reg, bytes));
  194 }
  195 
  196 /* 
  197  * Write configuration space register 
  198  */
  199 void
  200 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
  201 {
  202 
  203         pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
  204 }
  205 
  206 /* 
  207  * Configuration space access using direct register operations
  208  */
  209 
  210 /* enable configuration space accesses and return data port address */
  211 static int
  212 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
  213 {
  214         int dataport = 0;
  215 
  216 #ifdef XBOX
  217         if (arch_i386_is_xbox) {
  218                 /*
  219                  * The Xbox MCPX chipset is a derivative of the nForce 1
  220                  * chipset. It almost has the same bus layout; some devices
  221                  * cannot be used, because they have been removed.
  222                  */
  223 
  224                 /*
  225                  * Devices 00:00.1 and 00:00.2 used to be memory controllers on
  226                  * the nForce chipset, but on the Xbox, using them will lockup
  227                  * the chipset.
  228                  */
  229                 if (bus == 0 && slot == 0 && (func == 1 || func == 2))
  230                         return dataport;
  231                 
  232                 /*
  233                  * Bus 1 only contains a VGA controller at 01:00.0. When you try
  234                  * to probe beyond that device, you only get garbage, which
  235                  * could cause lockups.
  236                  */
  237                 if (bus == 1 && (slot != 0 || func != 0))
  238                         return dataport;
  239                 
  240                 /*
  241                  * Bus 2 used to contain the AGP controller, but the Xbox MCPX
  242                  * doesn't have one. Probing it can cause lockups.
  243                  */
  244                 if (bus >= 2)
  245                         return dataport;
  246         }
  247 #endif
  248 
  249         if (bus <= PCI_BUSMAX
  250             && slot < devmax
  251             && func <= PCI_FUNCMAX
  252             && reg <= PCI_REGMAX
  253             && bytes != 3
  254             && (unsigned) bytes <= 4
  255             && (reg & (bytes - 1)) == 0) {
  256                 switch (cfgmech) {
  257                 case CFGMECH_1:
  258                         outl(CONF1_ADDR_PORT, (1 << 31)
  259                             | (bus << 16) | (slot << 11) 
  260                             | (func << 8) | (reg & ~0x03));
  261                         dataport = CONF1_DATA_PORT + (reg & 0x03);
  262                         break;
  263                 case CFGMECH_2:
  264                         outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
  265                         outb(CONF2_FORWARD_PORT, bus);
  266                         dataport = 0xc000 | (slot << 8) | reg;
  267                         break;
  268                 }
  269         }
  270         return (dataport);
  271 }
  272 
  273 /* disable configuration space accesses */
  274 static void
  275 pci_cfgdisable(void)
  276 {
  277         switch (cfgmech) {
  278         case CFGMECH_1:
  279                 outl(CONF1_ADDR_PORT, 0);
  280                 break;
  281         case CFGMECH_2:
  282                 outb(CONF2_ENABLE_PORT, 0);
  283                 outb(CONF2_FORWARD_PORT, 0);
  284                 break;
  285         }
  286 }
  287 
  288 static int
  289 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
  290 {
  291         int data = -1;
  292         int port;
  293 
  294         if (cfgmech == CFGMECH_PCIE) {
  295                 data = pciereg_cfgread(bus, slot, func, reg, bytes);
  296                 return (data);
  297         }
  298 
  299         mtx_lock_spin(&pcicfg_mtx);
  300         port = pci_cfgenable(bus, slot, func, reg, bytes);
  301         if (port != 0) {
  302                 switch (bytes) {
  303                 case 1:
  304                         data = inb(port);
  305                         break;
  306                 case 2:
  307                         data = inw(port);
  308                         break;
  309                 case 4:
  310                         data = inl(port);
  311                         break;
  312                 }
  313                 pci_cfgdisable();
  314         }
  315         mtx_unlock_spin(&pcicfg_mtx);
  316         return (data);
  317 }
  318 
  319 static void
  320 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
  321 {
  322         int port;
  323 
  324         if (cfgmech == CFGMECH_PCIE) {
  325                 pciereg_cfgwrite(bus, slot, func, reg, data, bytes);
  326                 return;
  327         }
  328 
  329         mtx_lock_spin(&pcicfg_mtx);
  330         port = pci_cfgenable(bus, slot, func, reg, bytes);
  331         if (port != 0) {
  332                 switch (bytes) {
  333                 case 1:
  334                         outb(port, data);
  335                         break;
  336                 case 2:
  337                         outw(port, data);
  338                         break;
  339                 case 4:
  340                         outl(port, data);
  341                         break;
  342                 }
  343                 pci_cfgdisable();
  344         }
  345         mtx_unlock_spin(&pcicfg_mtx);
  346 }
  347 
  348 /* check whether the configuration mechanism has been correctly identified */
  349 static int
  350 pci_cfgcheck(int maxdev)
  351 {
  352         uint32_t id, class;
  353         uint8_t header;
  354         uint8_t device;
  355         int port;
  356 
  357         if (bootverbose) 
  358                 printf("pci_cfgcheck:\tdevice ");
  359 
  360         for (device = 0; device < maxdev; device++) {
  361                 if (bootverbose) 
  362                         printf("%d ", device);
  363 
  364                 port = pci_cfgenable(0, device, 0, 0, 4);
  365                 id = inl(port);
  366                 if (id == 0 || id == 0xffffffff)
  367                         continue;
  368 
  369                 port = pci_cfgenable(0, device, 0, 8, 4);
  370                 class = inl(port) >> 8;
  371                 if (bootverbose)
  372                         printf("[class=%06x] ", class);
  373                 if (class == 0 || (class & 0xf870ff) != 0)
  374                         continue;
  375 
  376                 port = pci_cfgenable(0, device, 0, 14, 1);
  377                 header = inb(port);
  378                 if (bootverbose)
  379                         printf("[hdr=%02x] ", header);
  380                 if ((header & 0x7e) != 0)
  381                         continue;
  382 
  383                 if (bootverbose)
  384                         printf("is there (id=%08x)\n", id);
  385 
  386                 pci_cfgdisable();
  387                 return (1);
  388         }
  389         if (bootverbose) 
  390                 printf("-- nothing found\n");
  391 
  392         pci_cfgdisable();
  393         return (0);
  394 }
  395 
  396 static int
  397 pcireg_cfgopen(void)
  398 {
  399         uint32_t mode1res, oldval1;
  400         uint8_t mode2res, oldval2;
  401 
  402         oldval1 = inl(CONF1_ADDR_PORT);
  403 
  404         if (bootverbose) {
  405                 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
  406                     oldval1);
  407         }
  408 
  409         if ((oldval1 & CONF1_ENABLE_MSK) == 0) {
  410 
  411                 cfgmech = CFGMECH_1;
  412                 devmax = 32;
  413 
  414                 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
  415                 DELAY(1);
  416                 mode1res = inl(CONF1_ADDR_PORT);
  417                 outl(CONF1_ADDR_PORT, oldval1);
  418 
  419                 if (bootverbose)
  420                         printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n", 
  421                             mode1res, CONF1_ENABLE_CHK);
  422 
  423                 if (mode1res) {
  424                         if (pci_cfgcheck(32)) 
  425                                 return (cfgmech);
  426                 }
  427 
  428                 outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
  429                 mode1res = inl(CONF1_ADDR_PORT);
  430                 outl(CONF1_ADDR_PORT, oldval1);
  431 
  432                 if (bootverbose)
  433                         printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n", 
  434                             mode1res, CONF1_ENABLE_CHK1);
  435 
  436                 if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
  437                         if (pci_cfgcheck(32)) 
  438                                 return (cfgmech);
  439                 }
  440         }
  441 
  442         oldval2 = inb(CONF2_ENABLE_PORT);
  443 
  444         if (bootverbose) {
  445                 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
  446                     oldval2);
  447         }
  448 
  449         if ((oldval2 & 0xf0) == 0) {
  450 
  451                 cfgmech = CFGMECH_2;
  452                 devmax = 16;
  453 
  454                 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
  455                 mode2res = inb(CONF2_ENABLE_PORT);
  456                 outb(CONF2_ENABLE_PORT, oldval2);
  457 
  458                 if (bootverbose)
  459                         printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
  460                             mode2res, CONF2_ENABLE_CHK);
  461 
  462                 if (mode2res == CONF2_ENABLE_RES) {
  463                         if (bootverbose)
  464                                 printf("pci_open(2a):\tnow trying mechanism 2\n");
  465 
  466                         if (pci_cfgcheck(16)) 
  467                                 return (cfgmech);
  468                 }
  469         }
  470 
  471         cfgmech = CFGMECH_NONE;
  472         devmax = 0;
  473         return (cfgmech);
  474 }
  475 
  476 static int
  477 pciereg_cfgopen(void)
  478 {
  479         struct pcie_cfg_list *pcielist;
  480         struct pcie_cfg_elem *pcie_array, *elem;
  481 #ifdef SMP
  482         struct pcpu *pc;
  483 #endif
  484         vm_offset_t va;
  485         int i;
  486 
  487         if (bootverbose)
  488                 printf("Setting up PCIe mappings for BAR 0x%x\n", pciebar);
  489 
  490 #ifdef SMP
  491         SLIST_FOREACH(pc, &cpuhead, pc_allcpu)
  492 #endif
  493         {
  494 
  495                 pcie_array = malloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE,
  496                     M_DEVBUF, M_NOWAIT);
  497                 if (pcie_array == NULL)
  498                         return (0);
  499 
  500                 va = kmem_alloc_nofault(kernel_map, PCIE_CACHE * PAGE_SIZE);
  501                 if (va == 0) {
  502                         free(pcie_array, M_DEVBUF);
  503                         return (0);
  504                 }
  505 
  506 #ifdef SMP
  507                 pcielist = &pcie_list[pc->pc_cpuid];
  508 #else
  509                 pcielist = &pcie_list[0];
  510 #endif
  511                 TAILQ_INIT(pcielist);
  512                 for (i = 0; i < PCIE_CACHE; i++) {
  513                         elem = &pcie_array[i];
  514                         elem->vapage = va + (i * PAGE_SIZE);
  515                         elem->papage = 0;
  516                         TAILQ_INSERT_HEAD(pcielist, elem, elem);
  517                 }
  518         }
  519 
  520         
  521         cfgmech = CFGMECH_PCIE;
  522         devmax = 32;
  523         return (1);
  524 }
  525 
  526 #define PCIE_PADDR(bar, reg, bus, slot, func)   \
  527         ((bar)                          |       \
  528         (((bus) & 0xff) << 20)          |       \
  529         (((slot) & 0x1f) << 15)         |       \
  530         (((func) & 0x7) << 12)          |       \
  531         ((reg) & 0xfff))
  532 
  533 /*
  534  * Find an element in the cache that matches the physical page desired, or
  535  * create a new mapping from the least recently used element.
  536  * A very simple LRU algorithm is used here, does it need to be more
  537  * efficient?
  538  */
  539 static __inline struct pcie_cfg_elem *
  540 pciereg_findelem(vm_paddr_t papage)
  541 {
  542         struct pcie_cfg_list *pcielist;
  543         struct pcie_cfg_elem *elem;
  544 
  545         pcielist = &pcie_list[PCPU_GET(cpuid)];
  546         TAILQ_FOREACH(elem, pcielist, elem) {
  547                 if (elem->papage == papage)
  548                         break;
  549         }
  550 
  551         if (elem == NULL) {
  552                 elem = TAILQ_LAST(pcielist, pcie_cfg_list);
  553                 if (elem->papage != 0) {
  554                         pmap_kremove(elem->vapage);
  555                         invlpg(elem->vapage);
  556                 }
  557                 pmap_kenter(elem->vapage, papage);
  558                 elem->papage = papage;
  559         }
  560 
  561         if (elem != TAILQ_FIRST(pcielist)) {
  562                 TAILQ_REMOVE(pcielist, elem, elem);
  563                 TAILQ_INSERT_HEAD(pcielist, elem, elem);
  564         }
  565         return (elem);
  566 }
  567 
  568 static int
  569 pciereg_cfgread(int bus, int slot, int func, int reg, int bytes)
  570 {
  571         struct pcie_cfg_elem *elem;
  572         volatile vm_offset_t va;
  573         vm_paddr_t pa, papage;
  574         int data;
  575 
  576         critical_enter();
  577         pa = PCIE_PADDR(pciebar, reg, bus, slot, func);
  578         papage = pa & ~PAGE_MASK;
  579         elem = pciereg_findelem(papage);
  580         va = elem->vapage | (pa & PAGE_MASK);
  581 
  582         switch (bytes) {
  583         case 4:
  584                 data = *(volatile uint32_t *)(va);
  585                 break;
  586         case 2:
  587                 data = *(volatile uint16_t *)(va);
  588                 break;
  589         case 1:
  590                 data = *(volatile uint8_t *)(va);
  591                 break;
  592         default:
  593                 panic("pciereg_cfgread: invalid width");
  594         }
  595 
  596         critical_exit();
  597         return (data);
  598 }
  599 
  600 static void
  601 pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
  602 {
  603         struct pcie_cfg_elem *elem;
  604         volatile vm_offset_t va;
  605         vm_paddr_t pa, papage;
  606 
  607         critical_enter();
  608         pa = PCIE_PADDR(pciebar, reg, bus, slot, func);
  609         papage = pa & ~PAGE_MASK;
  610         elem = pciereg_findelem(papage);
  611         va = elem->vapage | (pa & PAGE_MASK);
  612 
  613         switch (bytes) {
  614         case 4:
  615                 *(volatile uint32_t *)(va) = data;
  616                 break;
  617         case 2:
  618                 *(volatile uint16_t *)(va) = data;
  619                 break;
  620         case 1:
  621                 *(volatile uint8_t *)(va) = data;
  622                 break;
  623         default:
  624                 panic("pciereg_cfgwrite: invalid width");
  625         }
  626 
  627         critical_exit();
  628 }

Cache object: cab7245a579545fafeb075638cbc2ba1


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