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 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                 /*
  280                  * Do nothing for the config mechanism 1 case.
  281                  * Writing a 0 to the address port can apparently
  282                  * confuse some bridges and cause spurious
  283                  * access failures.
  284                  */
  285                 break;
  286         case CFGMECH_2:
  287                 outb(CONF2_ENABLE_PORT, 0);
  288                 break;
  289         }
  290 }
  291 
  292 static int
  293 pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
  294 {
  295         int data = -1;
  296         int port;
  297 
  298         if (cfgmech == CFGMECH_PCIE) {
  299                 data = pciereg_cfgread(bus, slot, func, reg, bytes);
  300                 return (data);
  301         }
  302 
  303         mtx_lock_spin(&pcicfg_mtx);
  304         port = pci_cfgenable(bus, slot, func, reg, bytes);
  305         if (port != 0) {
  306                 switch (bytes) {
  307                 case 1:
  308                         data = inb(port);
  309                         break;
  310                 case 2:
  311                         data = inw(port);
  312                         break;
  313                 case 4:
  314                         data = inl(port);
  315                         break;
  316                 }
  317                 pci_cfgdisable();
  318         }
  319         mtx_unlock_spin(&pcicfg_mtx);
  320         return (data);
  321 }
  322 
  323 static void
  324 pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
  325 {
  326         int port;
  327 
  328         if (cfgmech == CFGMECH_PCIE) {
  329                 pciereg_cfgwrite(bus, slot, func, reg, data, bytes);
  330                 return;
  331         }
  332 
  333         mtx_lock_spin(&pcicfg_mtx);
  334         port = pci_cfgenable(bus, slot, func, reg, bytes);
  335         if (port != 0) {
  336                 switch (bytes) {
  337                 case 1:
  338                         outb(port, data);
  339                         break;
  340                 case 2:
  341                         outw(port, data);
  342                         break;
  343                 case 4:
  344                         outl(port, data);
  345                         break;
  346                 }
  347                 pci_cfgdisable();
  348         }
  349         mtx_unlock_spin(&pcicfg_mtx);
  350 }
  351 
  352 /* check whether the configuration mechanism has been correctly identified */
  353 static int
  354 pci_cfgcheck(int maxdev)
  355 {
  356         uint32_t id, class;
  357         uint8_t header;
  358         uint8_t device;
  359         int port;
  360 
  361         if (bootverbose) 
  362                 printf("pci_cfgcheck:\tdevice ");
  363 
  364         for (device = 0; device < maxdev; device++) {
  365                 if (bootverbose) 
  366                         printf("%d ", device);
  367 
  368                 port = pci_cfgenable(0, device, 0, 0, 4);
  369                 id = inl(port);
  370                 if (id == 0 || id == 0xffffffff)
  371                         continue;
  372 
  373                 port = pci_cfgenable(0, device, 0, 8, 4);
  374                 class = inl(port) >> 8;
  375                 if (bootverbose)
  376                         printf("[class=%06x] ", class);
  377                 if (class == 0 || (class & 0xf870ff) != 0)
  378                         continue;
  379 
  380                 port = pci_cfgenable(0, device, 0, 14, 1);
  381                 header = inb(port);
  382                 if (bootverbose)
  383                         printf("[hdr=%02x] ", header);
  384                 if ((header & 0x7e) != 0)
  385                         continue;
  386 
  387                 if (bootverbose)
  388                         printf("is there (id=%08x)\n", id);
  389 
  390                 pci_cfgdisable();
  391                 return (1);
  392         }
  393         if (bootverbose) 
  394                 printf("-- nothing found\n");
  395 
  396         pci_cfgdisable();
  397         return (0);
  398 }
  399 
  400 static int
  401 pcireg_cfgopen(void)
  402 {
  403         uint32_t mode1res, oldval1;
  404         uint8_t mode2res, oldval2;
  405 
  406         /* Check for type #1 first. */
  407         oldval1 = inl(CONF1_ADDR_PORT);
  408 
  409         if (bootverbose) {
  410                 printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
  411                     oldval1);
  412         }
  413 
  414         cfgmech = CFGMECH_1;
  415         devmax = 32;
  416 
  417         outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
  418         DELAY(1);
  419         mode1res = inl(CONF1_ADDR_PORT);
  420         outl(CONF1_ADDR_PORT, oldval1);
  421 
  422         if (bootverbose)
  423                 printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n",  mode1res,
  424                     CONF1_ENABLE_CHK);
  425 
  426         if (mode1res) {
  427                 if (pci_cfgcheck(32)) 
  428                         return (cfgmech);
  429         }
  430 
  431         outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
  432         mode1res = inl(CONF1_ADDR_PORT);
  433         outl(CONF1_ADDR_PORT, oldval1);
  434 
  435         if (bootverbose)
  436                 printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n",  mode1res,
  437                     CONF1_ENABLE_CHK1);
  438 
  439         if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
  440                 if (pci_cfgcheck(32)) 
  441                         return (cfgmech);
  442         }
  443 
  444         /* Type #1 didn't work, so try type #2. */
  445         oldval2 = inb(CONF2_ENABLE_PORT);
  446 
  447         if (bootverbose) {
  448                 printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
  449                     oldval2);
  450         }
  451 
  452         if ((oldval2 & 0xf0) == 0) {
  453 
  454                 cfgmech = CFGMECH_2;
  455                 devmax = 16;
  456 
  457                 outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
  458                 mode2res = inb(CONF2_ENABLE_PORT);
  459                 outb(CONF2_ENABLE_PORT, oldval2);
  460 
  461                 if (bootverbose)
  462                         printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n", 
  463                             mode2res, CONF2_ENABLE_CHK);
  464 
  465                 if (mode2res == CONF2_ENABLE_RES) {
  466                         if (bootverbose)
  467                                 printf("pci_open(2a):\tnow trying mechanism 2\n");
  468 
  469                         if (pci_cfgcheck(16)) 
  470                                 return (cfgmech);
  471                 }
  472         }
  473 
  474         /* Nothing worked, so punt. */
  475         cfgmech = CFGMECH_NONE;
  476         devmax = 0;
  477         return (cfgmech);
  478 }
  479 
  480 static int
  481 pciereg_cfgopen(void)
  482 {
  483         struct pcie_cfg_list *pcielist;
  484         struct pcie_cfg_elem *pcie_array, *elem;
  485 #ifdef SMP
  486         struct pcpu *pc;
  487 #endif
  488         vm_offset_t va;
  489         int i;
  490 
  491         if (bootverbose)
  492                 printf("Setting up PCIe mappings for BAR 0x%x\n", pciebar);
  493 
  494 #ifdef SMP
  495         SLIST_FOREACH(pc, &cpuhead, pc_allcpu)
  496 #endif
  497         {
  498 
  499                 pcie_array = malloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE,
  500                     M_DEVBUF, M_NOWAIT);
  501                 if (pcie_array == NULL)
  502                         return (0);
  503 
  504                 va = kmem_alloc_nofault(kernel_map, PCIE_CACHE * PAGE_SIZE);
  505                 if (va == 0) {
  506                         free(pcie_array, M_DEVBUF);
  507                         return (0);
  508                 }
  509 
  510 #ifdef SMP
  511                 pcielist = &pcie_list[pc->pc_cpuid];
  512 #else
  513                 pcielist = &pcie_list[0];
  514 #endif
  515                 TAILQ_INIT(pcielist);
  516                 for (i = 0; i < PCIE_CACHE; i++) {
  517                         elem = &pcie_array[i];
  518                         elem->vapage = va + (i * PAGE_SIZE);
  519                         elem->papage = 0;
  520                         TAILQ_INSERT_HEAD(pcielist, elem, elem);
  521                 }
  522         }
  523 
  524         
  525         cfgmech = CFGMECH_PCIE;
  526         devmax = 32;
  527         return (1);
  528 }
  529 
  530 #define PCIE_PADDR(bar, reg, bus, slot, func)   \
  531         ((bar)                          |       \
  532         (((bus) & 0xff) << 20)          |       \
  533         (((slot) & 0x1f) << 15)         |       \
  534         (((func) & 0x7) << 12)          |       \
  535         ((reg) & 0xfff))
  536 
  537 /*
  538  * Find an element in the cache that matches the physical page desired, or
  539  * create a new mapping from the least recently used element.
  540  * A very simple LRU algorithm is used here, does it need to be more
  541  * efficient?
  542  */
  543 static __inline struct pcie_cfg_elem *
  544 pciereg_findelem(vm_paddr_t papage)
  545 {
  546         struct pcie_cfg_list *pcielist;
  547         struct pcie_cfg_elem *elem;
  548 
  549         pcielist = &pcie_list[PCPU_GET(cpuid)];
  550         TAILQ_FOREACH(elem, pcielist, elem) {
  551                 if (elem->papage == papage)
  552                         break;
  553         }
  554 
  555         if (elem == NULL) {
  556                 elem = TAILQ_LAST(pcielist, pcie_cfg_list);
  557                 if (elem->papage != 0) {
  558                         pmap_kremove(elem->vapage);
  559                         invlpg(elem->vapage);
  560                 }
  561                 pmap_kenter(elem->vapage, papage);
  562                 elem->papage = papage;
  563         }
  564 
  565         if (elem != TAILQ_FIRST(pcielist)) {
  566                 TAILQ_REMOVE(pcielist, elem, elem);
  567                 TAILQ_INSERT_HEAD(pcielist, elem, elem);
  568         }
  569         return (elem);
  570 }
  571 
  572 static int
  573 pciereg_cfgread(int bus, int slot, int func, int reg, int bytes)
  574 {
  575         struct pcie_cfg_elem *elem;
  576         volatile vm_offset_t va;
  577         vm_paddr_t pa, papage;
  578         int data;
  579 
  580         critical_enter();
  581         pa = PCIE_PADDR(pciebar, reg, bus, slot, func);
  582         papage = pa & ~PAGE_MASK;
  583         elem = pciereg_findelem(papage);
  584         va = elem->vapage | (pa & PAGE_MASK);
  585 
  586         switch (bytes) {
  587         case 4:
  588                 data = *(volatile uint32_t *)(va);
  589                 break;
  590         case 2:
  591                 data = *(volatile uint16_t *)(va);
  592                 break;
  593         case 1:
  594                 data = *(volatile uint8_t *)(va);
  595                 break;
  596         default:
  597                 panic("pciereg_cfgread: invalid width");
  598         }
  599 
  600         critical_exit();
  601         return (data);
  602 }
  603 
  604 static void
  605 pciereg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
  606 {
  607         struct pcie_cfg_elem *elem;
  608         volatile vm_offset_t va;
  609         vm_paddr_t pa, papage;
  610 
  611         critical_enter();
  612         pa = PCIE_PADDR(pciebar, reg, bus, slot, func);
  613         papage = pa & ~PAGE_MASK;
  614         elem = pciereg_findelem(papage);
  615         va = elem->vapage | (pa & PAGE_MASK);
  616 
  617         switch (bytes) {
  618         case 4:
  619                 *(volatile uint32_t *)(va) = data;
  620                 break;
  621         case 2:
  622                 *(volatile uint16_t *)(va) = data;
  623                 break;
  624         case 1:
  625                 *(volatile uint8_t *)(va) = data;
  626                 break;
  627         default:
  628                 panic("pciereg_cfgwrite: invalid width");
  629         }
  630 
  631         critical_exit();
  632 }

Cache object: 9f3c3c86ce569c7350b9dcb4ac08f3c8


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