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$");
   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 supported chipsets */
  163         vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2);
  164         did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2);
  165         if (vid == 0x8086) {
  166                 if (did == 0x3590 || did == 0x3592) {
  167                         /* Intel 7520 or 7320 */
  168                         pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16;
  169                         pciereg_cfgopen();
  170                 } else if (did == 0x2580 || did == 0x2584) {
  171                         /* Intel 915 or 925 */
  172                         pciebar = pci_cfgregread(0, 0, 0, 0x48, 4);
  173                         pciereg_cfgopen();
  174                 }
  175         }
  176 
  177         return(1);
  178 }
  179 
  180 /* 
  181  * Read configuration space register
  182  */
  183 u_int32_t
  184 pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
  185 {
  186         uint32_t line;
  187 
  188         /*
  189          * Some BIOS writers seem to want to ignore the spec and put
  190          * 0 in the intline rather than 255 to indicate none.  The rest of
  191          * the code uses 255 as an invalid IRQ.
  192          */
  193         if (reg == PCIR_INTLINE && bytes == 1) {
  194                 line = pcireg_cfgread(bus, slot, func, PCIR_INTLINE, 1);
  195                 return (pci_i386_map_intline(line));
  196         }
  197         return (pcireg_cfgread(bus, slot, func, reg, bytes));
  198 }
  199 
  200 /* 
  201  * Write configuration space register 
  202  */
  203 void
  204 pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
  205 {
  206 
  207         pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
  208 }
  209 
  210 /* 
  211  * Configuration space access using direct register operations
  212  */
  213 
  214 /* enable configuration space accesses and return data port address */
  215 static int
  216 pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
  217 {
  218         int dataport = 0;
  219 
  220 #ifdef XBOX
  221         if (arch_i386_is_xbox) {
  222                 /*
  223                  * The Xbox MCPX chipset is a derivative of the nForce 1
  224                  * chipset. It almost has the same bus layout; some devices
  225                  * cannot be used, because they have been removed.
  226                  */
  227 
  228                 /*
  229                  * Devices 00:00.1 and 00:00.2 used to be memory controllers on
  230                  * the nForce chipset, but on the Xbox, using them will lockup
  231                  * the chipset.
  232                  */
  233                 if (bus == 0 && slot == 0 && (func == 1 || func == 2))
  234                         return dataport;
  235                 
  236                 /*
  237                  * Bus 1 only contains a VGA controller at 01:00.0. When you try
  238                  * to probe beyond that device, you only get garbage, which
  239                  * could cause lockups.
  240                  */
  241                 if (bus == 1 && (slot != 0 || func != 0))
  242                         return dataport;
  243                 
  244                 /*
  245                  * Bus 2 used to contain the AGP controller, but the Xbox MCPX
  246                  * doesn't have one. Probing it can cause lockups.
  247                  */
  248                 if (bus >= 2)
  249                         return dataport;
  250         }
  251 #endif
  252 
  253         if (bus <= PCI_BUSMAX
  254             && slot < devmax
  255             && func <= PCI_FUNCMAX
  256             && reg <= PCI_REGMAX
  257             && bytes != 3
  258             && (unsigned) bytes <= 4
  259             && (reg & (bytes - 1)) == 0) {
  260                 switch (cfgmech) {
  261                 case CFGMECH_1:
  262                         outl(CONF1_ADDR_PORT, (1 << 31)
  263                             | (bus << 16) | (slot << 11) 
  264                             | (func << 8) | (reg & ~0x03));
  265                         dataport = CONF1_DATA_PORT + (reg & 0x03);
  266                         break;
  267                 case CFGMECH_2:
  268                         outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
  269                         outb(CONF2_FORWARD_PORT, bus);
  270                         dataport = 0xc000 | (slot << 8) | reg;
  271                         break;
  272                 }
  273         }
  274         return (dataport);
  275 }
  276 
  277 /* disable configuration space accesses */
  278 static void
  279 pci_cfgdisable(void)
  280 {
  281         switch (cfgmech) {
  282         case CFGMECH_1:
  283                 /*
  284                  * Do nothing for the config mechanism 1 case.
  285                  * Writing a 0 to the address port can apparently
  286                  * confuse some bridges and cause spurious
  287                  * access failures.
  288                  */
  289                 break;
  290         case CFGMECH_2:
  291                 outb(CONF2_ENABLE_PORT, 0);
  292                 break;
  293         }
  294 }
  295 
  296 static int
  297 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
  298 {
  299         int data = -1;
  300         int port;
  301 
  302         if (cfgmech == CFGMECH_PCIE) {
  303                 data = pciereg_cfgread(bus, slot, func, reg, bytes);
  304                 return (data);
  305         }
  306 
  307         mtx_lock_spin(&pcicfg_mtx);
  308         port = pci_cfgenable(bus, slot, func, reg, bytes);
  309         if (port != 0) {
  310                 switch (bytes) {
  311                 case 1:
  312                         data = inb(port);
  313                         break;
  314                 case 2:
  315                         data = inw(port);
  316                         break;
  317                 case 4:
  318                         data = inl(port);
  319                         break;
  320                 }
  321                 pci_cfgdisable();
  322         }
  323         mtx_unlock_spin(&pcicfg_mtx);
  324         return (data);
  325 }
  326 
  327 static void
  328 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
  329 {
  330         int port;
  331 
  332         if (cfgmech == CFGMECH_PCIE) {
  333                 pciereg_cfgwrite(bus, slot, func, reg, data, bytes);
  334                 return;
  335         }
  336 
  337         mtx_lock_spin(&pcicfg_mtx);
  338         port = pci_cfgenable(bus, slot, func, reg, bytes);
  339         if (port != 0) {
  340                 switch (bytes) {
  341                 case 1:
  342                         outb(port, data);
  343                         break;
  344                 case 2:
  345                         outw(port, data);
  346                         break;
  347                 case 4:
  348                         outl(port, data);
  349                         break;
  350                 }
  351                 pci_cfgdisable();
  352         }
  353         mtx_unlock_spin(&pcicfg_mtx);
  354 }
  355 
  356 /* check whether the configuration mechanism has been correctly identified */
  357 static int
  358 pci_cfgcheck(int maxdev)
  359 {
  360         uint32_t id, class;
  361         uint8_t header;
  362         uint8_t device;
  363         int port;
  364 
  365         if (bootverbose) 
  366                 printf("pci_cfgcheck:\tdevice ");
  367 
  368         for (device = 0; device < maxdev; device++) {
  369                 if (bootverbose) 
  370                         printf("%d ", device);
  371 
  372                 port = pci_cfgenable(0, device, 0, 0, 4);
  373                 id = inl(port);
  374                 if (id == 0 || id == 0xffffffff)
  375                         continue;
  376 
  377                 port = pci_cfgenable(0, device, 0, 8, 4);
  378                 class = inl(port) >> 8;
  379                 if (bootverbose)
  380                         printf("[class=%06x] ", class);
  381                 if (class == 0 || (class & 0xf870ff) != 0)
  382                         continue;
  383 
  384                 port = pci_cfgenable(0, device, 0, 14, 1);
  385                 header = inb(port);
  386                 if (bootverbose)
  387                         printf("[hdr=%02x] ", header);
  388                 if ((header & 0x7e) != 0)
  389                         continue;
  390 
  391                 if (bootverbose)
  392                         printf("is there (id=%08x)\n", id);
  393 
  394                 pci_cfgdisable();
  395                 return (1);
  396         }
  397         if (bootverbose) 
  398                 printf("-- nothing found\n");
  399 
  400         pci_cfgdisable();
  401         return (0);
  402 }
  403 
  404 static int
  405 pcireg_cfgopen(void)
  406 {
  407         uint32_t mode1res, oldval1;
  408         uint8_t mode2res, oldval2;
  409 
  410         /* Check for type #1 first. */
  411         oldval1 = inl(CONF1_ADDR_PORT);
  412 
  413         if (bootverbose) {
  414                 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
  415                     oldval1);
  416         }
  417 
  418         cfgmech = CFGMECH_1;
  419         devmax = 32;
  420 
  421         outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
  422         DELAY(1);
  423         mode1res = inl(CONF1_ADDR_PORT);
  424         outl(CONF1_ADDR_PORT, oldval1);
  425 
  426         if (bootverbose)
  427                 printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n",  mode1res,
  428                     CONF1_ENABLE_CHK);
  429 
  430         if (mode1res) {
  431                 if (pci_cfgcheck(32)) 
  432                         return (cfgmech);
  433         }
  434 
  435         outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
  436         mode1res = inl(CONF1_ADDR_PORT);
  437         outl(CONF1_ADDR_PORT, oldval1);
  438 
  439         if (bootverbose)
  440                 printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n",  mode1res,
  441                     CONF1_ENABLE_CHK1);
  442 
  443         if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
  444                 if (pci_cfgcheck(32)) 
  445                         return (cfgmech);
  446         }
  447 
  448         /* Type #1 didn't work, so try type #2. */
  449         oldval2 = inb(CONF2_ENABLE_PORT);
  450 
  451         if (bootverbose) {
  452                 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
  453                     oldval2);
  454         }
  455 
  456         if ((oldval2 & 0xf0) == 0) {
  457 
  458                 cfgmech = CFGMECH_2;
  459                 devmax = 16;
  460 
  461                 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
  462                 mode2res = inb(CONF2_ENABLE_PORT);
  463                 outb(CONF2_ENABLE_PORT, oldval2);
  464 
  465                 if (bootverbose)
  466                         printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
  467                             mode2res, CONF2_ENABLE_CHK);
  468 
  469                 if (mode2res == CONF2_ENABLE_RES) {
  470                         if (bootverbose)
  471                                 printf("pci_open(2a):\tnow trying mechanism 2\n");
  472 
  473                         if (pci_cfgcheck(16)) 
  474                                 return (cfgmech);
  475                 }
  476         }
  477 
  478         /* Nothing worked, so punt. */
  479         cfgmech = CFGMECH_NONE;
  480         devmax = 0;
  481         return (cfgmech);
  482 }
  483 
  484 static int
  485 pciereg_cfgopen(void)
  486 {
  487         struct pcie_cfg_list *pcielist;
  488         struct pcie_cfg_elem *pcie_array, *elem;
  489 #ifdef SMP
  490         struct pcpu *pc;
  491 #endif
  492         vm_offset_t va;
  493         int i;
  494 
  495         if (bootverbose)
  496                 printf("Setting up PCIe mappings for BAR 0x%x\n", pciebar);
  497 
  498 #ifdef SMP
  499         SLIST_FOREACH(pc, &cpuhead, pc_allcpu)
  500 #endif
  501         {
  502 
  503                 pcie_array = malloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE,
  504                     M_DEVBUF, M_NOWAIT);
  505                 if (pcie_array == NULL)
  506                         return (0);
  507 
  508                 va = kmem_alloc_nofault(kernel_map, PCIE_CACHE * PAGE_SIZE);
  509                 if (va == 0) {
  510                         free(pcie_array, M_DEVBUF);
  511                         return (0);
  512                 }
  513 
  514 #ifdef SMP
  515                 pcielist = &pcie_list[pc->pc_cpuid];
  516 #else
  517                 pcielist = &pcie_list[0];
  518 #endif
  519                 TAILQ_INIT(pcielist);
  520                 for (i = 0; i < PCIE_CACHE; i++) {
  521                         elem = &pcie_array[i];
  522                         elem->vapage = va + (i * PAGE_SIZE);
  523                         elem->papage = 0;
  524                         TAILQ_INSERT_HEAD(pcielist, elem, elem);
  525                 }
  526         }
  527 
  528         
  529         cfgmech = CFGMECH_PCIE;
  530         devmax = 32;
  531         return (1);
  532 }
  533 
  534 #define PCIE_PADDR(bar, reg, bus, slot, func)   \
  535         ((bar)                          |       \
  536         (((bus) & 0xff) << 20)          |       \
  537         (((slot) & 0x1f) << 15)         |       \
  538         (((func) & 0x7) << 12)          |       \
  539         ((reg) & 0xfff))
  540 
  541 /*
  542  * Find an element in the cache that matches the physical page desired, or
  543  * create a new mapping from the least recently used element.
  544  * A very simple LRU algorithm is used here, does it need to be more
  545  * efficient?
  546  */
  547 static __inline struct pcie_cfg_elem *
  548 pciereg_findelem(vm_paddr_t papage)
  549 {
  550         struct pcie_cfg_list *pcielist;
  551         struct pcie_cfg_elem *elem;
  552 
  553         pcielist = &pcie_list[PCPU_GET(cpuid)];
  554         TAILQ_FOREACH(elem, pcielist, elem) {
  555                 if (elem->papage == papage)
  556                         break;
  557         }
  558 
  559         if (elem == NULL) {
  560                 elem = TAILQ_LAST(pcielist, pcie_cfg_list);
  561                 if (elem->papage != 0) {
  562                         pmap_kremove(elem->vapage);
  563                         invlpg(elem->vapage);
  564                 }
  565                 pmap_kenter(elem->vapage, papage);
  566                 elem->papage = papage;
  567         }
  568 
  569         if (elem != TAILQ_FIRST(pcielist)) {
  570                 TAILQ_REMOVE(pcielist, elem, elem);
  571                 TAILQ_INSERT_HEAD(pcielist, elem, elem);
  572         }
  573         return (elem);
  574 }
  575 
  576 static int
  577 pciereg_cfgread(int bus, int slot, int func, int reg, int bytes)
  578 {
  579         struct pcie_cfg_elem *elem;
  580         volatile vm_offset_t va;
  581         vm_paddr_t pa, papage;
  582         int data;
  583 
  584         critical_enter();
  585         pa = PCIE_PADDR(pciebar, reg, bus, slot, func);
  586         papage = pa & ~PAGE_MASK;
  587         elem = pciereg_findelem(papage);
  588         va = elem->vapage | (pa & PAGE_MASK);
  589 
  590         switch (bytes) {
  591         case 4:
  592                 data = *(volatile uint32_t *)(va);
  593                 break;
  594         case 2:
  595                 data = *(volatile uint16_t *)(va);
  596                 break;
  597         case 1:
  598                 data = *(volatile uint8_t *)(va);
  599                 break;
  600         default:
  601                 panic("pciereg_cfgread: invalid width");
  602         }
  603 
  604         critical_exit();
  605         return (data);
  606 }
  607 
  608 static void
  609 pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
  610 {
  611         struct pcie_cfg_elem *elem;
  612         volatile vm_offset_t va;
  613         vm_paddr_t pa, papage;
  614 
  615         critical_enter();
  616         pa = PCIE_PADDR(pciebar, reg, bus, slot, func);
  617         papage = pa & ~PAGE_MASK;
  618         elem = pciereg_findelem(papage);
  619         va = elem->vapage | (pa & PAGE_MASK);
  620 
  621         switch (bytes) {
  622         case 4:
  623                 *(volatile uint32_t *)(va) = data;
  624                 break;
  625         case 2:
  626                 *(volatile uint16_t *)(va) = data;
  627                 break;
  628         case 1:
  629                 *(volatile uint8_t *)(va) = data;
  630                 break;
  631         default:
  632                 panic("pciereg_cfgwrite: invalid width");
  633         }
  634 
  635         critical_exit();
  636 }

Cache object: 34ed14b503f6d76c9ebca48048f8184e


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