root/arch/x86/pci/mmconfig_64.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pci_dev_base
  2. pci_mmcfg_read
  3. pci_mmcfg_write
  4. mcfg_ioremap
  5. pci_mmcfg_arch_init
  6. pci_mmcfg_arch_free
  7. pci_mmcfg_arch_map
  8. pci_mmcfg_arch_unmap

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
   4  *
   5  * This is an 64bit optimized version that always keeps the full mmconfig
   6  * space mapped. This allows lockless config space operation.
   7  */
   8 
   9 #include <linux/pci.h>
  10 #include <linux/init.h>
  11 #include <linux/acpi.h>
  12 #include <linux/bitmap.h>
  13 #include <linux/rcupdate.h>
  14 #include <asm/e820/api.h>
  15 #include <asm/pci_x86.h>
  16 
  17 #define PREFIX "PCI: "
  18 
  19 static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
  20 {
  21         struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
  22 
  23         if (cfg && cfg->virt)
  24                 return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12));
  25         return NULL;
  26 }
  27 
  28 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
  29                           unsigned int devfn, int reg, int len, u32 *value)
  30 {
  31         char __iomem *addr;
  32 
  33         /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
  34         if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
  35 err:            *value = -1;
  36                 return -EINVAL;
  37         }
  38 
  39         rcu_read_lock();
  40         addr = pci_dev_base(seg, bus, devfn);
  41         if (!addr) {
  42                 rcu_read_unlock();
  43                 goto err;
  44         }
  45 
  46         switch (len) {
  47         case 1:
  48                 *value = mmio_config_readb(addr + reg);
  49                 break;
  50         case 2:
  51                 *value = mmio_config_readw(addr + reg);
  52                 break;
  53         case 4:
  54                 *value = mmio_config_readl(addr + reg);
  55                 break;
  56         }
  57         rcu_read_unlock();
  58 
  59         return 0;
  60 }
  61 
  62 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
  63                            unsigned int devfn, int reg, int len, u32 value)
  64 {
  65         char __iomem *addr;
  66 
  67         /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
  68         if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
  69                 return -EINVAL;
  70 
  71         rcu_read_lock();
  72         addr = pci_dev_base(seg, bus, devfn);
  73         if (!addr) {
  74                 rcu_read_unlock();
  75                 return -EINVAL;
  76         }
  77 
  78         switch (len) {
  79         case 1:
  80                 mmio_config_writeb(addr + reg, value);
  81                 break;
  82         case 2:
  83                 mmio_config_writew(addr + reg, value);
  84                 break;
  85         case 4:
  86                 mmio_config_writel(addr + reg, value);
  87                 break;
  88         }
  89         rcu_read_unlock();
  90 
  91         return 0;
  92 }
  93 
  94 const struct pci_raw_ops pci_mmcfg = {
  95         .read =         pci_mmcfg_read,
  96         .write =        pci_mmcfg_write,
  97 };
  98 
  99 static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg)
 100 {
 101         void __iomem *addr;
 102         u64 start, size;
 103         int num_buses;
 104 
 105         start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
 106         num_buses = cfg->end_bus - cfg->start_bus + 1;
 107         size = PCI_MMCFG_BUS_OFFSET(num_buses);
 108         addr = ioremap_nocache(start, size);
 109         if (addr)
 110                 addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
 111         return addr;
 112 }
 113 
 114 int __init pci_mmcfg_arch_init(void)
 115 {
 116         struct pci_mmcfg_region *cfg;
 117 
 118         list_for_each_entry(cfg, &pci_mmcfg_list, list)
 119                 if (pci_mmcfg_arch_map(cfg)) {
 120                         pci_mmcfg_arch_free();
 121                         return 0;
 122                 }
 123 
 124         raw_pci_ext_ops = &pci_mmcfg;
 125 
 126         return 1;
 127 }
 128 
 129 void __init pci_mmcfg_arch_free(void)
 130 {
 131         struct pci_mmcfg_region *cfg;
 132 
 133         list_for_each_entry(cfg, &pci_mmcfg_list, list)
 134                 pci_mmcfg_arch_unmap(cfg);
 135 }
 136 
 137 int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
 138 {
 139         cfg->virt = mcfg_ioremap(cfg);
 140         if (!cfg->virt) {
 141                 pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res);
 142                 return -ENOMEM;
 143         }
 144 
 145         return 0;
 146 }
 147 
 148 void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
 149 {
 150         if (cfg && cfg->virt) {
 151                 iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
 152                 cfg->virt = NULL;
 153         }
 154 }

/* [<][>][^][v][top][bottom][index][help] */